useCallback把匿名回調“存”起來
在之前版本的文檔和大牛的blog中都有提到避免在component render時候聲明匿名方法,因爲這些匿名方法會被反覆重新聲明而無法被多次利用,然後容易造成component反覆不必要的渲染。
在Class component當中我們通常將回調函數聲明爲類成員:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.clickCallback = this.clickCallback.bind(this);
}
clickCallback() {
// ...
}
render() {
return <button onClick={this.clickCallback}>Click Me!</button>;
}
}
使用useCallback hook就可以避免bind操作:
function MyComponent(props) {
const clickCallback = React.useCallback(() => {
// ...
}, []);
return <button onClick={clickCallback}>Click Me!</button>;
}
這個回調也可以接收參數:
function MyComponent(props) {
const clickCallback = React.useCallback((value) => {
// ...
}, []);
const clickCallbackEmpty = React.useCallback(() => clickCallback(void 0), [clickCallback]);
return <button onClick={clickCallbackEmpty}>Click Me!</button>;
}
這裏我爲了不使用匿名函數,額外再聲明瞭一個clickCallbackEmpty回調函數。看起來挺奇怪的,不過實際使用過程中爲了提高代碼重用性不可避免地有一些這樣的用法。
除此之外,如果想避免使用匿名回調,並且必須要傳入一些事件對象裏沒有的參數,那就要考慮拆分component了。
同useEffect一樣,useCallback的第二個參數是用於比較memo的上下文中對應值是否變化,如果有變化則會重新聲明回調函數。如果這個參數爲空數組,則只會在component掛載時運行。如果不存在這個參數,則會在每次渲染時運行。
上例中,clickCallbackEmpty聲明時的第二個參數裏,傳入了clickCallback,因爲我在clickCallbackEmpty中調用了clickCallback。我只需要在component掛載時,和clickCallback發生變化時,更新clickCallbackEmpty就好。
實際上監測clickCallback變化在上例中是沒有什麼卵用的,因爲我的clickCallback並不會變化,它的值已經在component掛載時就敲定了。但爲了後續增刪代碼防止出錯,個人建議還是加上比較好。
useMemo保存一些計算值
從component props中獲得原始數據, 計算、轉換格式後再顯示是非常常見的需求。使用useMemo可以輕鬆防止不必要的重複計算。
function MyComponent(props) {
const computedVal = useMemo(() =>
props.a + props.b,
[props.a, props.b]
);
return <div>{computedVal}</div>;
}
實際上useCallback就等同於
useMemo(() => callback, [var1, var2, ...]);