大家好,我是前端西瓜哥。最近做的新功能有性能问题,所以想尝试优化React组件的性能。让我们学习如何使用React.memo。组件状态更新和重新渲染当组件中的状态发生变化时,React会调用组件的render方法生成新的React元素树,将其与原来的虚拟DOM进行比较,找出差异并交给真实的DOM补丁。如果有子组件,它也会被重新渲染。这里有个问题:有些子组件实际上并没有改变状态,但也重新渲染,占用CPU资源。虽然这个操作是不必要的,但React无法知道传递给子组件的props是否发生了变化。但是React提供了React.memo()方法,希望你可以用它来告诉React组件是否跳过重新渲染。React.memoReact.memo是一个高阶组件。所谓高阶组件,其实就是指接收一个组件,返回一个组件的函数。名字指的是高阶函数,但确实有点花哨。React.memo的作用是缓存组件。它会为传入的组件生成一个具有缓存功能的新组件,然后返回这个新组件。在传递给组件的props的属性和值没有发生变化的情况下,它会使用最新的缓存结果而不用重新渲染,达到跳过组件渲染的效果。下面是一个例子:constComp=({color})=>{return(
);};//生成一个可以缓存结果的组件constMemoryedComp=React.memo(Comp);当我们使用MemoriedBox时,如果传递的props.color保持不变,MemoriedBox组件将不会重新渲染。这是一个演示示例:https://codesandbox.io/s/react-memo-huan-cun-ce-shi-k96vd4。保证道具的有效比较算法。React.memo判断是否使用缓存。默认是浅比较,即只比较第一层的key。shallowEqual主要是通过Object.is来比较的。源码实现地址如下:https://github.com/facebook/react/blob/HEAD/packages/shared/shallowEqual.js。有时我们想自定义比较方法。这时候我们可以使用React.memo方法的第二个参数传入我们自定义的比较方法。constisEqual(prevProps,nextProps){//自定义比较方法}constMemoriedComp=React.memo(Comp,isEqual);自定义的比较方法会得到两个参数:新老props对象,然后根据方法返回值来决定是否使用缓存。如果为真,则使用缓存,否则重新渲染并缓存新的渲染结果。假设我们有一个prop是一个数组,但是因为在组件中写了声明语句,所以每次渲染都会生成另一个指向新内存空间的数组,导致新旧props指向不同的内存对象,但它们的数组元素顺序相等。[1,2]===[1,2]//false有时我们希望将它们视为“相同”,以便能够触发React.memo方法的缓存。使用浅比较会返回false并重新渲染,这不是我们所期望的。这时候可以使用自己的深度比较(deeprecursivecomparison),可以考虑使用比较有名的lodash.isEqual。缓存函数对于数组和普通对象,我们可以通过深度比较来判断“相等”。但是对于函数组件中每次都会rebuild的函数,显然是行不通的。函数没有结构。对于函数,我们可以使用useCallback。constComp=()=>{constonClick=React.useCallback(()=>{if(isOk)sumbit();},[isOk])return(
)}useCallback接受一个函数和一个依赖数组。当依赖数组中的元素没有变化时,将使用最后一个缓存的函数,否则将使用传入的新函数。除了使用useCallback来缓存函数,我们还可以使用useMemo来缓存其他对象值。避免对仅渲染一次且之后不会更新的组件进行负优化,不要使用React.memo。每次props都会变化的组件,不要使用React.memo,使用React.memo只会带来不必要的新旧props对比和无意义的缓存。如果组件非常简单,不建议使用React.memo,它不会带来太大的提升,而且使用React.memo本身就有精神负担。如果不能很好地量化性能,不推荐使用React.memo。最后React.memo可以帮助我们跳过一些不必要的组件渲染。但是要保持objecttypeprop不变,确实会给我们带来很大的精神负担。React.memo不一定有积极的好处,因为缓存也有成本。