1.函數組件使用memo
當父組件給子組件傳遞了props的時候,如果在父組件沒有加判斷子組件條件性渲染,eg: {isShowChild&& },每次父組件執行render,子組件(函數)都會重新渲染(執行),這時候如果是在子組件用memo導出,eg:
const Child = (props) => {
return <div>那一夜{props.ChildName}</div>
}
export default React.memo(C)
當到子組件時,會淺比較子組件的前後props值,如果props的每個屬性值都一樣,就會跳過函數組件Child的執行,減少不必要渲染。
memo的第二個參數函數,默認有兩個參數當前props和之前的props,我們可以判斷比較我們想監控的props中某個或者某些值來決定是否渲染,最後return false即會重新執行該組件。
React.memo(C, (nextProps, prevProps) => {
// 做我們想做的事情,類似shouldComponentUpdate
})
2.函數組件中props爲函數
js中函數即對象,每個對象指向的地址不同,這兩個對象就算結構和值相同,最後也不會“===”,所以function(){}不會等於function(){},在函數組件中,eg:
export default () => {
const myFunc = () => {}
return (
<div>
<Child onClick={myFunc} />
</div>
)
}
每次這個函數組件重新渲染,即重新執行,函數作用域都會重新構建,相當於myFunc重新聲明瞭兩次,前後肯定不會“===”,但是我們的函數其實是做同一件事,並不需要它跟着父組件渲染。這裏我們可以自己構造另外一個參數{flag:true,myFunc: myFunc},在導出函數子組件的時候:
React.memo(Child, (nextProps, prevProps) => nextProps.flag === prevProps.flag)
這個其實就是上個說的根據前後props中檢測其中的某個我們想比較的值或者業務邏輯來判斷是否要重新執行渲染。
ps:在class組件中,我們綁定在class上的this.myFunc一直都是同一個函數。這種情況,子組件爲函數組件的時候,包一層memo就可以實現purecomponent的效果。
3.使用useCallback來判斷相同的函數
上次提到了把props的函數放到父函數組件的外面可以避免函數組件重新執行後的重新聲明構造,但那是沒有函數參數依賴的情況下,否則還是要把函數寫在組件裏面。
useCallback有兩個參數Function(,[],第一個即爲我們要傳入的函數,第二個爲決定前後是否是同一個函數的依賴。eg:
export default () => {
const myFunc = useCallback(() => {}, []);
// dep即爲依賴參數,dep不變,myFunc始終是一個函數,dep變化,myFunc即變化。
const handleClick1 = useCallback(() => {}, [dep]);
return (
<div>
<IfEqual onClick={handleClick} />
</div>
)
}
同情情況適用於函數組件本身,組件本身也是一個函數。
export default () => {
const myFunc = useCallback(() => {}, []);
const myComponent = useCallback(({ name }) => {
return <button onClick={myFunc}>{name}</button>
}, [handleClick]);
return (
<div>
<myComponent name="Jack" />
</div>
)
}
4.使用useMemo來節省相同的計算結果(函數返回)
當一個函數是做計算任務時,會阻塞到js主線程,如果參數一樣,在純函數計算模式下,返回的結果也應該一樣,所以我們希望參數一樣的情況下不會重新執行函數組件。這就需要使用useMemo:
const a = useMemo(() => memorizeValue, deps)
//memorizeValue爲函數的時候 等於useCallBack
useCallback(fn, inputs) <=> useMemo(() => fn, inputs)
eg:
// useMemo記憶結果的一個自定義hook
function myCalcuTasks(n) {
const res = useMemo(() => {
return CalcuTasks(n);
}, [n])
return res;
}
當CalcuTasks是一個很大計算任務時,如果在函數組件中調用到myCalcuTasks,第一次渲染肯定會卡住一會,當本函數組件重新渲染/執行時,如果n值沒有變時,此計算函數會直接返回上次記憶結果,不會重新執行一遍。但注意傳入的n變化,會重新執行函數重新計算。