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

React + Chakra UI 颜色模式切换后刷新/导航闪烁问题求助

Chakra UI 颜色模式切换后刷新/导航闪烁问题的解决思路

问题描述

React + Chakra UI项目中,初始设置为深色模式,切换到浅色模式后刷新或导航,页面会先闪烁深色再切换到正确模式;反之亦然。通过打印useColorMode()的加载值,发现加载时会先返回light再返回dark(或顺序相反)。

相关代码

index.tsx

import { ChakraProvider, ColorModeScript } from "@chakra-ui/react"
import * as React from "react"
import * as ReactDOM from "react-dom/client"
import { App } from "./App"
import reportWebVitals from "./reportWebVitals"
import * as serviceWorker from "./serviceWorker"
import theme from "../src/theme"

const container = document.getElementById("root")
if (!container) throw new Error('Failed to find the root element');
const root = ReactDOM.createRoot(container)

root.render(
  <React.StrictMode>
    <ChakraProvider theme={theme}>
    <ColorModeScript initialColorMode={theme.config.initialColorMode} />
      <App />
    </ChakraProvider>
  </React.StrictMode>,
)

App.tsx

import HeaderNavbar from "./Components/Header/Header"
import Footer from "./Components/Footer/Footer"
import { Home } from "../src/Pages/Home/Home"
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import { About } from "../src/Pages/About/About";

export const App = () => {
  return (
    <>
      <HeaderNavbar />
      <Router>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
        </Routes>
      </Router>
      <Footer/>
    </>
  );
};

theme.ts

import { extendTheme, type ThemeConfig } from '@chakra-ui/react'

const config: ThemeConfig = {
  initialColorMode: "dark",
  useSystemColorMode: false,
}

const theme = extendTheme({ config })

export default theme

解决思路

这个问题是Chakra UI官方明确的已知问题,核心原因是React hydration过程中,初始颜色模式与本地存储的用户选择模式不一致,导致渲染时先显示初始模式,再切换到用户设置的模式,从而产生闪烁。以下是具体解决方案:

  1. 调整ColorModeScript的位置
    ColorModeScript是直接操作DOM的脚本,必须放在ChakraProvider外部,确保在Chakra初始化前注入。修改index.tsx的渲染结构:

    root.render(
      <>
        <ColorModeScript initialColorMode={theme.config.initialColorMode} />
        <React.StrictMode>
          <ChakraProvider theme={theme}>
            <App />
          </ChakraProvider>
        </React.StrictMode>
      </>
    )
    
  2. 动态同步本地存储的颜色模式
    用户切换模式后,Chakra会将选择存在localStorage的chakra-ui-color-mode键中。初始化时优先读取该值,确保初始渲染直接使用用户的选择:

    // index.tsx中添加
    const getInitialColorMode = () => {
      if (typeof window !== 'undefined') {
        const storedMode = window.localStorage.getItem('chakra-ui-color-mode');
        return storedMode || theme.config.initialColorMode;
      }
      return theme.config.initialColorMode;
    };
    
    // 渲染时传入动态获取的初始模式
    root.render(
      <>
        <ColorModeScript initialColorMode={getInitialColorMode()} />
        <React.StrictMode>
          <ChakraProvider theme={theme}>
            <App />
          </ChakraProvider>
        </React.StrictMode>
      </>
    )
    
  3. 添加初始加载的样式隐藏
    在public/index.html的<head>中添加CSS,在颜色模式未初始化完成前隐藏页面,避免闪烁:

    <style>
      body {
        visibility: hidden;
      }
      body.chakra-ui-light, body.chakra-ui-dark {
        visibility: visible;
      }
    </style>
    

    Chakra会在颜色模式初始化后给<body>添加对应的类名,页面只有在模式确定后才会显示。

  4. 排查React StrictMode的影响
    开发环境下React StrictMode会触发两次渲染,可能导致模式值被重复设置。可以暂时关闭StrictMode测试是否是该原因,生产环境下StrictMode不会产生此问题,或者调整逻辑避免重复触发模式切换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 11:27:08