You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functionChild(props){console.log('Child render');return(<p>
name is
{props.data.name}</p>);}Child=memo(Child);functionApp(){const[count,setCount]=useState(0);const[name,setName]=useState('Mary');console.log('Parent render');constdata={ name };return(<div><p>
click
{' '}{count}{' '}
times
</p><Childdata={data}/><buttontype="button"onClick={()=>{setCount(count+1);}}>+</button><buttontype="button"onClick={()=>{setName(`${Date.now()}`);}}>change Name</button></div>);}
但是我们发现,这样修改后,运行结果仍然没变,即使name没有变化,父组件count变化后,Child还是render了,原因是setCount后,整个App函数都重新执行,data = { name } 相当于重新生成了一个新的对象,所以Child还是render了。
解决这个问题的一个解决方案就是上面提到的:useMemo
functionChild(props){console.log('Child render');return(<buttontype="button"onClick={props.addClick}>{props.data.count}</button>);}Child=memo(Child);functionApp(){const[count,setCount]=useState(0);const[name,setName]=useState('Mary');constdata=useMemo(()=>({ count }),[count]);constaddClick=()=>{setCount(count+1);};return(<div><p>
name is :
{' '}{name}</p><Childdata={data}addClick={addClick}/><buttontype="button"onClick={()=>{setName(`${Date.now()}`);}}>change Name</button></div>);}
useMemo
useMemo作用
常常用于缓存一些复杂计算的结果。useMemo 接收一个函数和依赖数组,当数组中依赖项变化的时候,这个函数就会执行,返回新的值。【对象做依赖的话,进行的是浅比较,也就是对比两个对象的引用是否相同】
举个例子会更加清楚 useMemo 的使用场景,我们就以下面这个 DatePicker 组件的计算为例:
DatePicker 组件每次打开或者切换月份的时候,都需要大量的计算来算出当前需要展示哪些日期。然后再将计算后的结果渲染到单元格里面,这里可以使用 useMemo 来缓存,只有当传入的日期变化时才去计算。
举例:
上述这个例子的执行结果为,点击+按钮或者change Name按钮,Child都会渲染,输出Child render
但是我们希望Child的render只依赖于它自己的props,不受其他影响,那么我们可以使用React.memo实现(React.memo 仅检查 props 变更)。我们改写例子如下
但是我们发现,这样修改后,运行结果仍然没变,即使name没有变化,父组件count变化后,Child还是render了,原因是setCount后,整个App函数都重新执行,data = { name } 相当于重新生成了一个新的对象,所以Child还是render了。
解决这个问题的一个解决方案就是上面提到的:useMemo
这样,我们发现光是count变化后,子组件就不渲染了
但是也要注意,要是依赖项为空,即使name变化,那么data也永远不变,Child也不渲染
useMemo实现原理
比较本次和上次依赖项的值,如果有一个变化,则重新计算callback的值并返回,如果未变化,则返回上次callback的值
useCallback
和 useMemo 类似,只不过 useCallback 是用来缓存函数。
匿名函数导致不必要的渲染
在我们编写 React 组件的时候,经常会用到事件处理函数,很多人都会简单粗暴的传一个箭头函数。
这种箭头函数有个问题,那就是在每一次组件重新渲染的时候都会生成一个重复的匿名箭头函数,导致传给组件的参数发生了变化,对性能造成一定的损耗。
在函数组件里面,同样会有这个传递新的匿名函数的问题。从下面这个例子来看,每次点击 change Name,就会导致Child渲染,通过useMemo我们已经知道,data不会变化,但是addClick每次在父组件渲染后都会生成一个新的方法,所以Child也跟着渲染了。
这就是体现 useCallback 价值的地方了,我们可以用 useCallback 指定依赖项。在无关更新之后,通过 useCallback 取的还是上一次缓存起来的函数。因此,useCallback 常常配合 React.memo 来一起使用,用于进行性能优化。
useCallback实现原理
参考:
1、React Hooks第一期:聊聊useCallback
https://zhuanlan.zhihu.com/p/56975681
2、手写实现react-hook:https://www.acfun.cn/v/ac16764934
The text was updated successfully, but these errors were encountered: