React组件性能优化

2024-04-14 1148阅读

React.memo

在React的工作流中,如果只有父组件的状态发生变化,即使传递给子组件的props和子组件本身的state都没有发生变化,子组件也会重新渲染。但是从React的声明式设计理念来看,如果子组件的Props和state都没有改变,那么其生成的DOM结构和副作用也不应该发生改变。当子组件符合声明式设计理念时,就可以忽略子组件本次的Render过程。React.memo就是用来解决这个问题的。当一个组件使用memo封装后,父组件状态变更,只要传递给该子组件的props和其自身状态没变化,子组件就不会重新渲染。

React组件性能优化
(图片来源网络,侵删)

建议复杂的组件、重新渲染成本高的组件都要使用memo封装后导出,比如典型的复杂表单或表格。

import React, {memo} from 'react';
const CustomTable = memo(() => {});
export default CustomTable;

useMemo、useCallback

传递给子组件的状态或者函数,如果每次都是一个新的引用,就会导致子组件经常重新渲染,即使子组件加上了memo,也会令其失效。这是因为React中判断状态是否变更使用的是浅比较,即对于对象函数这类来说只是单纯比较引用是否一致。

下面的写法都会使得子组件渲染频繁:

 {xxx}} />

这个时候就需要使用useMemo来生成稳定的值,useCallback生成稳定的函数。只有当依赖发生变化的时候,才会重新计算值,防止触发不必要的渲染。

针对函数的缓存,也可以使用ahook提供的useMemoizedFn生成一个永远不会变的函数,且不需要声明依赖的状态,每次调用都会取最新依赖值。基本可以代替useCallback的使用,要注意的是useMemoizedFn所生成的函数和原函数引用完全不同,且不会继承原函数的属性,比如原型这些。

事例演示:

演示说明:

options是对象,直接写到属性中会每次生成新的值。TestDemo这类复杂组件,重新渲染成本高,建议缓存,错误示例如下

{
        aa: 'aaa',
        bb: 'bbb',
        cc: {
            dd: 'ddd'
        }
    }}
/

使用useMemo封装TestDemo ,对传入的对象类属性也用useMemo进行封装,正确示例如下:

// 事件监听函数直接定义,每次都是新的引用,所以用useMemoizedFn封装
const handleClick = useMemoizedFn(() => {});
const options = useMemo(() => {
    return {
        aa: 'aaa',
        bb: 'bbb',
        cc: {
            dd: 'ddd'
        }
    }
}, []);
return (
    
);

使用上下文解决跨层级数据传递问题

如果使用props向下传递的方式实现跨层级数据传递,中间的组件即使没有用到该状态值,只是传递,当该状态发生变化的时候,也会触发更新。这个时候就可以使用上下文Context来进行数据传递,确保只有真正用到该值的组件重新渲染。

要注意的是使用Context通常都是多个组件共用数据的情况,对该数据的变化要遵循非必要不更新的原则,绝对不可直接传递引用值。

// 此写法每次父组件重新渲染,该值都会变化导致用到该context的子组件都会重新渲染

全局状态变化

使用recoil创建的状态为全局状态,全局状态应遵循以下规范:

1、每个状态单一职责,不要一个大对象里面放各种值

2、不应该经常变化。

3、严控数据修改范围,尽可能不暴露给使用者修改方法,避免滥用。

列表渲染每一个列表项一定要加key且唯一,不可用索引

当插入一个新的数据在最前面的时候,使用索引作为key语不加key是一样的效果,达不到优化。

批量更新state,统一渲染一次

多个state的更新有的时候是批量更新统一渲染一次的,有的时候是多次更新渲染多次的,如果把握不好更新的时机,很容易造成组件多次渲染。

在React的事件处理函数(比如点击事件)、生命周期方法(如componentDidMount)和钩子函数如(useEffect中的回调)中同步更新state的时候,React会自动批量更新,只渲染一次。

useEffect(() => {
   // 生命周期中同步更新,react会批量更新
   setList({...Data.list});
   setInfo({...Data.info});
}, []);
const onClick = () => {
   // 事件中同步更新,react会批量更新
   setList({...Data.list});
   setInfo({...Data.info});
}

而在其它地方、或者在上面的场景中异步更新都不会自动触发React的批量更新

useEffect(() => {
    // 生命周期中异步更新,react会批量更新
    setTimeout(() => {
        setList({...Data.list});
        setInfo({...Data.info});
    })
}, []);
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]