You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Chakra网站响应式开发中无样式内容闪烁问题求助

解决Chakra UI useBreakpointValue导致的初始渲染闪烁问题

我在React + Chakra UI项目中开发响应式布局时碰到了问题:使用useBreakpointValue({ base: false, lg: true })判断屏幕尺寸,但钩子返回值前页面已经完成初始渲染,导致页面出现无样式内容闪烁,等钩子返回值后才重新渲染为正确样式。

问题代码

import { Box, Flex, Image, Stack, Text, useBreakpointValue, Heading } from "@chakra-ui/react";
import React from "react";
import { LoginForm } from "./login_form";
import { colors } from "theme/colors";
import { useNavigate } from 'react-router-dom';
import { RouterPaths } from "router/routerConfig";

const Login: React.FC = () => {
const navigate = useNavigate();

const handleLogin = () => {
  console.log('Login clicked');
  navigate(RouterPaths.REGISTER); // Navigate to the next page after login
};

const isLargeScreen = useBreakpointValue({ base: false, lg: true });
const effectiveIsLargeScreen = typeof isLargeScreen === 'undefined' ? true : isLargeScreen;

return (
  <Flex direction="column" h="100vh">
    {!isLargeScreen && (
      <Flex direction="row" bg={colors.primary[500]} p="5">
        <Heading m="auto" color="white">Drop Here</Heading>
      </Flex>
    )}

    <Flex direction="row" >
      {isLargeScreen && (
        <Box w="50%" bg={colors.primary[500]} >
          <Stack direction="column" p="50" h="100vh" spacing={4}>
            <Flex alignItems="center">
              <Image src="/images/White_T.png" w="14" />
              <Text fontSize="30px" fontWeight="800" color="white" ml={-2}>Drop Here</Text>
            </Flex>

            <Text fontSize="40px" fontWeight="600" color="white" pt="20%" lineHeight="shorter">
              Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
            </Text>

            <Text minW={400} color="white">
              Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
            </Text>

            <Box display="flex" flexDirection="column" justifyContent="flex-end" height="100vh">
              <Text fontWeight={300} color="white">© {new Date().getFullYear()} Drop Here. All rights reserved</Text>
            </Box>
          </Stack>
        </Box>
      )}
      <LoginForm onLogin={handleLogin} />
    </Flex>
  </Flex>
);
};

export default Login;

解决方案

方案1:使用effectiveIsLargeScreen替代所有isLargeScreen引用

你已经定义了effectiveIsLargeScreen但没用到,这个变量能在钩子返回值前提供默认值,避免初始渲染时isLargeScreen为undefined导致的错误布局。把所有条件判断里的isLargeScreen换成这个变量,初始渲染就会使用默认值,等钩子返回正确值后再更新,减少闪烁:

// ... 其他代码不变
const isLargeScreen = useBreakpointValue({ base: false, lg: true });
const effectiveIsLargeScreen = typeof isLargeScreen === 'undefined' ? true : isLargeScreen;

return (
  <Flex direction="column" h="100vh">
    {!effectiveIsLargeScreen && (
      <Flex direction="row" bg={colors.primary[500]} p="5">
        <Heading m="auto" color="white">Drop Here</Heading>
      </Flex>
    )}

    <Flex direction="row" >
      {effectiveIsLargeScreen && (
        <Box w="50%" bg={colors.primary[500]} >
          {/* 侧边栏内容不变 */}
        </Box>
      )}
      <LoginForm onLogin={handleLogin} />
    </Flex>
  </Flex>
);

方案2:用Chakra UI响应式Props替代条件渲染(推荐)

条件渲染会导致DOM元素的添加/删除,这是闪烁的根本原因。Chakra UI支持直接在组件属性上写响应式值,通过CSS媒体查询控制显示/隐藏,不需要依赖useBreakpointValue,从根源解决闪烁问题:

import { Box, Flex, Image, Stack, Text, Heading } from "@chakra-ui/react";
import React from "react";
import { LoginForm } from "./login_form";
import { colors } from "theme/colors";
import { useNavigate } from 'react-router-dom';
import { RouterPaths } from "router/routerConfig";

const Login: React.FC = () => {
const navigate = useNavigate();

const handleLogin = () => {
  console.log('Login clicked');
  navigate(RouterPaths.REGISTER);
};

return (
  <Flex direction="column" h="100vh">
    {/* 小屏幕显示,大屏幕隐藏 */}
    <Flex direction="row" bg={colors.primary[500]} p="5" display={{ base: 'flex', lg: 'none' }}>
      <Heading m="auto" color="white">Drop Here</Heading>
    </Flex>

    <Flex direction="row" >
      {/* 大屏幕显示,小屏幕隐藏+宽度为0 */}
      <Box 
        w={{ base: 0, lg: '50%' }} 
        bg={colors.primary[500]} 
        display={{ base: 'none', lg: 'block' }}
      >
        <Stack direction="column" p="50" h="100vh" spacing={4}>
          <Flex alignItems="center">
            <Image src="/images/White_T.png" w="14" />
            <Text fontSize="30px" fontWeight="800" color="white" ml={-2}>Drop Here</Text>
          </Flex>

          <Text fontSize="40px" fontWeight="600" color="white" pt="20%" lineHeight="shorter">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
          </Text>

          <Text minW={400} color="white">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
          </Text>

          <Box display="flex" flexDirection="column" justifyContent="flex-end" height="100vh">
            <Text fontWeight={300} color="white">© {new Date().getFullYear()} Drop Here. All rights reserved</Text>
          </Box>
        </Stack>
      </Box>
      <LoginForm onLogin={handleLogin} />
    </Flex>
  </Flex>
);
};

export default Login;

这种方式下,所有元素一开始就存在于DOM中,只是通过CSS媒体查询根据屏幕尺寸控制显示/隐藏,不会有两次渲染的过程,彻底消除闪烁。

内容的提问来源于stack exchange,提问作者Sayuru_Sandaru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:20:08