createGlobalStyle不响应主题变化,因其仅首次渲染插值;须用函数式写法${(props) => :root { --color-primary: ${props.theme.primary}; }}并确保ThemeContext有效,否则变量不更新。

createGlobalStyle 不响应主题变化,这是最常踩的坑。它只在首次渲染时插值一次,后续主题更新不会触发重计算 —— 所以你看到变量没变、样式没更新,不是主题没传进去,而是全局样式根本没重跑。
为什么 createGlobalStyle 必须用函数式写法?
Emotion 的 createGlobalStyle 接收模板字符串或函数。传字符串是静态的,传函数才能拿到 props.theme 并实时计算 CSS 变量:
- 错误写法:
createGlobalStyle`:root { --color-primary: ${theme.primary}; }`——theme是闭包里固定值,换主题不生效 - 正确写法:
createGlobalStyle`${(props) => `:root { --color-primary: ${props.theme.primary}; }`}`—— 每次 re-render 都重新生成 CSS 字符串 - 必须确保该组件被
ThemeProvider包裹,且props.theme真实来自 Emotion 上下文,不是手动传参
useTheme 在普通组件里返回 undefined 怎么办?
这个 Hook 只在 Emotion 渲染链路中有效:要么是 styled 创建的组件,要么用了 css 或 GlobalStyles。纯 function 组件调用它,就是 undefined。
- 如果你只是想读主题值,改用
useContext(ThemeContext)(需import { ThemeContext } from 'emotion-react') - 如果要写主题感知逻辑但又不想用 styled,建议把主题状态提到顶层 Context,让
ThemeProvider和业务逻辑共用同一份 state - 别在
useEffect里依赖useTheme做副作用,容易因上下文缺失导致逻辑跳过
切换主题时闪一下(FOUC)怎么压?
闪烁不是 Emotion 的 bug,而是浏览器渲染时机问题:DOM 已渲染,但 :root 变量还没注入或没生效。
- 预埋默认值:在 HTML 的
<style>标签里写一层基础:root,避免首屏无变量可用 - 同步设置
document.documentElement.style:主题变更时立刻写入关键变量,比如document.documentElement.style.setProperty('--color-bg', theme.bg) - Next.js 场景下必须处理 SSR:服务端渲染时无法读取用户偏好,得靠 cookie 或 fallback 主题,否则 hydration mismatch 导致两次渲染


















