Emotion性能问题根源在于重复计算、无效缓存和SSR样式泄漏;需稳定css引用、服务端提取关键CSS并重置缓存、手动管理global/keyframes生命周期。

Emotion 在 JS 中写 CSS 本身不慢,真正影响性能的是重复计算、无效缓存、服务端渲染时的样式泄漏——内存问题几乎全出在这三处。
css 函数调用频繁但没复用,导致缓存失效
每次渲染都新建 css 调用,哪怕参数完全一样,也会绕过缓存重新哈希、序列化、插入 style 标签。这不是“写法错”,而是没意识到 css 是纯函数,必须手动稳定引用。
- 错误写法:
function Button({ primary }) { const s = css({ color: primary ? 'blue' : 'gray' }); return <button css="{s}">...</button> }—— 每次 render 都新建对象,缓存无法命中 - 正确做法:把样式提取到组件外,或用
useMemo包裹动态部分:const baseStyle = css({ padding: '8px 16px' }); const dynamicStyle = useMemo(() => css({ color: primary ? 'blue' : 'gray' }), [primary]) - 更推荐:用
styled+ 变量插值,它内部已做 memoization:const StyledButton = styled.button(({ primary }) => ({ color: primary ? 'blue' : 'gray' }))
服务端渲染未提取关键 CSS,导致客户端重复注入
SSR 场景下,若没调用 extractCritical 或 renderStylesToString,服务端生成的 HTML 不含内联样式,客户端 hydration 时会重新执行所有 css 调用——不仅多跑一遍逻辑,还可能触发多次 insertRule,造成 style 标签反复增删,引发 layout thrashing 和内存抖动。
- Node 端必须捕获样式:
const { css, html } = renderStylesToString(app),再把css插入<head> - 客户端 hydration 前需清空 Emotion 的运行时缓存(仅限 SSR 场景):
cache.reset(),否则服务端注入的规则和客户端新生成的规则可能冲突 - 注意
@emotion/server的版本兼容性:v11 要求与@emotion/react主版本一致,混用会导致缓存 key 错位,内存占用翻倍
全局样式或 keyframes 未清理,造成缓存长期驻留
global 和 keyframes 创建的规则默认永不释放——它们被设计为“应用生命周期级”,但实际项目中常因主题切换、微前端子应用卸载等场景需要手动回收。
立即学习“前端免费学习笔记(深入)”;
-
global样式建议用useInsertionEffect+ 清理函数管理生命周期:useInsertionEffect(() => { const cleanup = insertGlobal(...); return cleanup }, []) -
keyframes名称必须唯一且可预测,避免用随机 ID;否则每次生成新名称,缓存就多存一份无用规则 - 检查
cache.sheet.tags数量,若持续增长且无下降,大概率是全局规则泄漏——这是最容易被忽略的内存缓慢增长点
Emotion 的缓存不是“越久越好”,它的高效依赖于你对样式生命周期的显式控制。没人帮你决定某个 css 对象该活多久,一旦脱离组件作用域或 SSR 上下文,就得自己动手清理。



















