1.函数组件使用memo
当父组件给子组件传递了props的时候,如果在父组件没有加判断子组件条件性渲染,eg: {isShowChild&&
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变化,会重新执行函数重新计算。