平时在用Hooks写react组件时,最常用的就是 useSate, useEffect, useRef。还有一些不常用的Hooks也需要熟悉,在优化提高渲染效率的时候有用。
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
返回一个 memoized 值。
把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
举个我们常写的例子
function Demo(){
const [leftCount, setLeftCount] = useState(0);
const [rightCount, setRightCount] = useSate(0);
const renderLeftTotle = ()=>{
return leftCount * 2;
};
const renderRightTotal = ()=>{
return rightCount * 3;
};
return <>
<div>左边总金额:{renderLeftTotle()}</div>
<div>右边总金额:{renderRightTotal()}</div>
<div>
<button onClick={() => setLeftCount(leftCount + 1)}>左边+1</button>
<button onClick={() => setRightCount(rightCount + 1)}>右边+1</button>
</div>
</>;
}
上面这组件维护了两个state,但不管是左边+1还是右边+1,两个renderTotal都会计算,虽然界面上看不出来(差异化渲染)。当只左边+1的时候,只需要计算更新左边数据就行了,右边的计算就是多余的操作。这种时候,我们就可以用useMemo来减少不必要的计算。
function Demo(){
const [leftCount, setLeftCount] = useState(0);
const [rightCount, setRightCount] = useSate(0);
const renderLeftTotle = useMemo(()=>{
return leftCount * 2;
}, [leftCount]);
const renderRightTotal = useMemo(()=>{
return rightCount * 3;
}, [rightCount]);
return <>
<div>左边总金额:{renderLeftTotle()}</div>
<div>右边总金额:{renderRightTotal()}</div>
<div>
<button onClick={() => setLeftCount(leftCount + 1)}>左边+1</button>
<button onClick={() => setRightCount(rightCount + 1)}>右边+1</button>
</div>
</>;
}
使用useMemo后,并将依赖值传递进去,此时仅当依赖值变化时才会重新执行renderTotal。
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
返回一个 memoized 回调函数。
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
useMemo和useCallback接收的参数都是一样,都是在其依赖项发生变化后才执行,都是返回缓存的值,区别在于useMemo返回的是函数运行的结果,useCallback返回的是函数。
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。
应用举例:
function Parent() {
const [leftCount, setLeftCount] = useState(0);
const [rightCount, setRightCount] = useSate(0);
const renderLeftTotle = useCallback(()=>{
return leftCount * 2;
}, [leftCount]);
const renderRightTotal = useCallback(()=>{
return rightCount * 3;
}, [rightCount]);
return <>
<ChildLeft renderLeftTotle={renderLeftTotle} />
<ChildRight renderRightTotal={renderRightTotal} />
<div>
<button onClick={() => setLeftCount(leftCount + 1)}>左边+1</button>
<button onClick={() => setRightCount(rightCount + 1)}>右边+1</button>
</div>
</>;
}
const ChildLeft = React.memo(function ({ renderLeftTotle }: any) {
return <div>左边总金额:{renderLeftTotle()}</div>
});
const ChildRight = React.memo(function ({ renderRightTotle }: any) {
return <div>右边总金额:{renderRightTotle()}</div>
});