useMemo是react中常被用来进行性能优化的hook,其原理是通过将函数,组件,变量等缓存,防止状态改变发生重渲染而导致的重复计算。所以本质上是将某一个值保存在内存中,重复渲染时可以避免重复大量的计算以及保证了值的一致性
第一种使用场景,缓存高计算量的内容
function App() {
const [number, setNumber] = useState(0)
const [dark, setDark] = useState(false)
const doubleNumber = slowFunction(number)
const themeStyles = {
backgroundColor: dark ? 'black' : 'white',
color:dark?'white':'black'
}
useEffect(() => {
console.log('theme change')//做出一些提示等
}, [themeStyles])
return (
<div className="App">
<input type="number" value={number} onChange={e => setNumber(parseInt(e.target.value))}/>
<button onClick={()=>setDark(prevDark=>!prevDark)}>Change Theme</button>
<div style={themeStyles}>{ doubleNumber}</div>
</div>
);
}
export default App;
function slowFunction(num) {
console.log('Calling Slow Function')
for (let i = 0; i <= 10_0000_0000; i++){ }
return num*2
}
如上图代码,当我们对setNumber时,重渲染会导致doubleNumber通过调用slowFunction进行赋值,而slowFunction时一个很耗时的操作。由于doubleNumber依赖number的变化,所以在这里的耗时操作是正常必需的,可以想象为一个网络请求等。但是当我们点击按钮切换主题时,也会导致重渲染,而number并没有发生改变,所以doubleNumber也不用变化,此时再调用slowFunction是耗时且不必要的。可以将doubleNumber使用useMemo封装,可以避免主题改变时的重复计算
const doubleNumber = useMemo(() => {
return slowFunction(number)
},[number])
第二种使用场景,需要保持一致性,防止不必要的Effect
修改了doubleNumber的重复计算问题后,上述代码还有一个问题。就是主题改变时,useEffect会产生回调。但是当我们修改number时,发生了重渲染,此时重新运行渲染函数,useEffect同样会产生回调。原因就是,虽然渲染前后themeStyles对象里的内容一致,但是实际上是不同的两个对象,所以useEffect检测到themeStyles引用的对象发生改变后,产生回调。同样可以通过useMemo缓存themeStyles对象来避免不正常的Effect
const themeStyles = useMemo(() => {
return {
backgroundColor: dark ? 'black' : 'white',
color:dark?'white':'black'
};
},[dark])