缓存与性能 #
基本概念 #
Emotion 使用缓存机制来存储已生成的样式,避免重复计算。理解缓存机制和性能优化技巧,可以帮助你构建更高效的应用。
Emotion 缓存 #
默认缓存 #
Emotion 默认创建一个全局缓存:
jsx
import { css } from '@emotion/react'
function App() {
return (
<div css={css`color: red;`}>
Hello
</div>
)
}
自定义缓存 #
使用 createCache 创建自定义缓存:
jsx
import { CacheProvider } from '@emotion/react'
import createCache from '@emotion/cache'
const myCache = createCache({
key: 'my-app',
prepend: true,
})
function App() {
return (
<CacheProvider value={myCache}>
<Application />
</CacheProvider>
)
}
缓存配置选项 #
jsx
const cache = createCache({
key: 'css',
prepend: false,
speedy: true,
container: typeof document !== 'undefined' ? document.head : null,
nonce: undefined,
stylisPlugins: [],
prefix: true,
})
| 选项 | 说明 |
|---|---|
| key | 生成的类名前缀 |
| prepend | 是否将样式插入到头部 |
| speedy | 使用快速模式(生产环境推荐) |
| container | 样式插入的容器元素 |
| nonce | CSP nonce 值 |
| stylisPlugins | Stylis 插件数组 |
性能优化技巧 #
1. 提取样式定义 #
将样式提取到组件外部,避免每次渲染重新创建:
❌ 不推荐:
jsx
function Component() {
const style = css`
padding: 20px;
background: #f5f5f5;
`
return <div css={style}>Content</div>
}
✅ 推荐:
jsx
const style = css`
padding: 20px;
background: #f5f5f5;
`
function Component() {
return <div css={style}>Content</div>
}
2. 使用 useMemo 缓存动态样式 #
对于依赖 props 的动态样式,使用 useMemo 缓存:
jsx
/** @jsxImportSource @emotion/react */
import { css, useMemo } from '@emotion/react'
function Component({ size, color }) {
const dynamicStyle = useMemo(() => css`
font-size: ${size}px;
color: ${color};
`, [size, color])
return <div css={dynamicStyle}>Content</div>
}
3. 避免内联对象 #
❌ 不推荐:每次渲染创建新对象
jsx
function Component() {
return (
<div css={{ padding: 20, margin: 10 }}>
Content
</div>
)
}
✅ 推荐:使用稳定的样式引用
jsx
const style = { padding: 20, margin: 10 }
function Component() {
return <div css={style}>Content</div>
}
4. 使用 styled 组件 #
对于大量重复的元素,styled 组件性能更好:
jsx
import styled from '@emotion/styled'
const Item = styled.li`
padding: 8px;
border-bottom: 1px solid #eee;
`
function List({ items }) {
return (
<ul>
{items.map(item => (
<Item key={item.id}>{item.name}</Item>
))}
</ul>
)
}
5. 减少样式计算 #
使用 CSS 变量减少动态样式计算:
jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
const containerStyle = css`
padding: var(--padding, 16px);
background: var(--bg, #f5f5f5);
color: var(--color, #333);
`
function Component({ padding, bg, color }) {
return (
<div
css={containerStyle}
style={{
'--padding': `${padding}px`,
'--bg': bg,
'--color': color,
}}
>
Content
</div>
)
}
样式复用 #
Mixin 模式 #
创建可复用的样式片段:
jsx
import { css } from '@emotion/react'
const mixins = {
flexCenter: css`
display: flex;
align-items: center;
justify-content: center;
`,
truncate: css`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`,
cardShadow: css`
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`,
smoothTransition: css`
transition: all 0.2s ease;
`,
}
function Card({ children }) {
return (
<div css={[mixins.cardShadow, mixins.smoothTransition]}>
{children}
</div>
)
}
样式函数 #
创建动态样式函数:
jsx
import { css } from '@emotion/react'
const getFlexStyles = (direction = 'row', justify = 'center', align = 'center') => css`
display: flex;
flex-direction: ${direction};
justify-content: ${justify};
align-items: ${align};
`
const getSpacingStyles = (padding = 16, margin = 0) => css`
padding: ${padding}px;
margin: ${margin}px;
`
选择器优化 #
避免深层嵌套 #
❌ 深层嵌套:
jsx
const Bad = styled.div`
& > section {
& > article {
& > div {
& > p {
color: red;
}
}
}
}
`
✅ 扁平选择器:
jsx
const Good = styled.div`
& p {
color: red;
}
`
使用组件选择器 #
jsx
import styled from '@emotion/styled'
const Icon = styled.span`
margin-right: 8px;
`
const Button = styled.button`
display: inline-flex;
align-items: center;
&:hover ${Icon} {
transform: translateX(4px);
}
`
动画性能 #
使用 transform 和 opacity #
优先使用 transform 和 opacity 实现动画:
jsx
import styled from '@emotion/styled'
const AnimatedCard = styled.div`
transition: transform 0.3s ease, opacity 0.3s ease;
&:hover {
transform: translateY(-4px);
opacity: 0.9;
}
`
will-change #
对于复杂动画,使用 will-change 提示浏览器:
jsx
const AnimatedElement = styled.div`
will-change: transform, opacity;
animation: ${keyframes} 1s ease;
`
contain #
使用 contain 属性优化渲染:
jsx
const Card = styled.div`
contain: layout style paint;
`
包体积优化 #
按需导入 #
只导入需要的模块:
jsx
import styled from '@emotion/styled'
import { css } from '@emotion/react'
Tree Shaking #
确保构建工具支持 Tree Shaking:
json
{
"sideEffects": false
}
代码分割 #
将样式组件按功能分割:
jsx
import lazy from '@emotion/styled'
const HeavyComponent = lazy(() => import('./HeavyComponent'))
性能监控 #
使用 React DevTools #
React DevTools 可以帮助你识别不必要的重渲染。
性能测量 #
jsx
import { Profiler } from 'react'
function onRenderCallback(
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime
) {
console.log(`${id} ${phase} took ${actualDuration}ms`)
}
function App() {
return (
<Profiler id="App" onRender={onRenderCallback}>
<Application />
</Profiler>
)
}
缓存命中率 #
监控缓存命中率:
jsx
const cache = createCache({ key: 'css' })
function getCacheStats() {
const inserted = Object.keys(cache.inserted).length
const registered = Object.keys(cache.registered).length
return { inserted, registered }
}
最佳实践总结 #
1. 样式定义 #
- 将样式提取到组件外部
- 使用
useMemo缓存动态样式 - 避免内联对象
2. 组件选择 #
- 简单样式使用
cssprop - 可复用组件使用
styled - 大量重复元素使用
styled
3. 动画优化 #
- 使用
transform和opacity - 使用
will-change提示 - 避免动画过多元素
4. 包体积 #
- 按需导入
- 支持 Tree Shaking
- 代码分割
下一步 #
掌握了缓存与性能优化后,继续学习 项目结构,了解如何组织 Emotion 项目代码。
最后更新:2026-03-28