React 的默认渲染机制
// 未使用 memo 的情况
function HelloWorld({ result }) {
console.log("HelloWorld被渲染~")
return <div>{result}</div>
}
-
默认行为:
- React 采用"自上而下"的递归渲染策略
- 当父组件重新渲染时,React 会自动重新渲染所有子组件
- React 不会自动比较 props 是否发生变化
- 这种机制确保 UI 与数据的一致性,但可能导致不必要的渲染
-
渲染过程:
父组件状态更新 ↓ 父组件重新渲染 ↓ 子组件函数被调用 ↓ 生成新的虚拟 DOM ↓ 进行 DOM 更新
memo 的工作机制
const HelloWorld = memo(function HelloWorld({ result }) {
console.log("HelloWorld被渲染~")
return <div>{result}</div>
})
-
浅比较机制:
memo会对组件的 props 进行浅比较(shallow compare)- 只有当 props 发生变化时,组件才会重新渲染
- 浅比较意味着只比较对象的第一层属性
-
渲染过程:
父组件状态更新 ↓ 父组件重新渲染 ↓ memo 进行 props 浅比较 ↓ props 未变化 → 使用之前的渲染结果 props 已变化 → 重新渲染子组件
具体示例分析
const App = () => {
const [count, setCount] = useState(0)
const result = useMemo(() => calcNumTotal(50), [])
return (
<div>
<h2>计数:{count}</h2>
<button onClick={() => setCount(count + 1)}>+1</button>
<HelloWorld result={result} />
</div>
)
}
不使用 memo 时的渲染流程:
- 点击按钮,
count更新 App组件重新渲染HelloWorld组件无条件重新渲染- 即使
result没有变化,子组件仍然渲染
使用 memo 时的渲染流程:
- 点击按钮,
count更新 App组件重新渲染memo对HelloWorld的 props 进行浅比较- 发现
result未变化,跳过子组件渲染 - 直接复用上一次的渲染结果
memo 的性能考虑
-
优点:
- 避免不必要的渲染
- 提高应用性能
- 减少不必要的计算
-
潜在成本:
- 进行 props 比较需要额外的计算开销
- 维护缓存结果需要额外的内存开销
-
使用建议:
- 组件经常接收相同 props
- 组件渲染开销较大
- 组件渲染结果相对稳定
总结
-
原理区别:
- 不使用
memo:遵循 React 的默认渲染机制,父组件更新导致子组件无条件更新 - 使用
memo:增加了 props 比较的环节,只在必要时更新子组件
- 不使用
-
性能影响:
- 不使用
memo:可能导致不必要的渲染,但没有比较 props 的开销 - 使用
memo:避免不必要的渲染,但有 props 比较的开销
- 不使用
-
最佳实践:
- 对于简单组件,可以不使用
memo - 对于复杂组件或频繁重渲染的组件,建议使用
memo - 配合
useMemo和useCallback使用效果更好
- 对于简单组件,可以不使用