react在业务中的常用优化手段

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

业务背景

前端优化是一个永恒的课题,在优化的过程中,我们需要结合具体的项目,确定优化的目标和预期,制定优化方案,同时做好优化技术后复盘。下面将介绍一些我在过去几年中写react代码中常用的优化细节。

为什么要做项目优化

1.减少用户流失

用户角度:页面加载快,操作响应及时,体验好

2.更好的创收

服务角度:减少页面请求的次数,减少请求使用的带宽,节省可观的资源

时间角度的优化

1.网络请求优化 减少DNS耗时,CDN,ServiceWorker和HTTP缓存,PWA等技术,tree-shaking,移除无用代码,代码分割,使用HTTP2,资源压缩

  1. 首屏加载优化

减少白屏时间,分屏分片加载,按需加载,预加载和预请求,资源离线缓存

  1. 渲染过程优化

GPU加速,减少DOM重排和重绘,资源预加载

基于react颗粒性的优化

减少非必要的渲染和计算

  • ShouldComponentUpdate
  • PureComponent和React.memo
  • unstable_batchedUpdates批量更新
  • useMemo和useCallback稳定props的值

其他业务优化

  • 图片组件懒加载(非可见元素滞后渲染,快速render)
  • 商品图片组件使用缩略图(快速渲染,减少网络开销)
  • 埋点系统的解耦:class Component(配置埋点文件,使用call和apply达到埋点的解耦),hooks重写 createElement和props.onClick监听达到无痕埋点

React输入大量表单渲染时的性能优化

方案建议:

  1. 运用debounce避免在输入时频繁大量的调用方法,重复的调用会对中大型应用产生影响性能,造成组件及其子树不必要地更新渲染。

  2. 运用shouldComponentUpdate来拦截父组件更新是造成的子组件的不必要更新,以减少render函数的执行。

业务背景:

大量的报告表单,在小程序和后台管理中渲染时,大量的canvas和form表单一次性渲染造成页面卡顿,在表单输入处理时的更新操作也会卡顿

问题原因:

技术排查后,发现这个输入框没有使用debounce降低接口调用的频率,整个页面的部分子组件也没有使用shouldComponentUpdate来避免不必要的render。即定制师每输入或修改一个字符,都会选择整个页面,并请求接口,继续渲染整个页面,从而产生了大量不必要的界面重复渲染,造成卡顿。

解决方案:

1. 使用debounce优化

InputA = reactComponentDebounce({
    triggerMs: DELAY,
})(Input)
复制代码

额外注意debounce发请求问题:

当第counter个接口返回数据时,若与当前调用次数不匹配时,应拒绝将错误数据渲染到页面

DebouncePatten(params, fnArray) {
    const current = ++COUNTER
    return fnArray.reduce((prev, cur) => prev.then(wrapWithCancel(cur)), Promise.resolve(params));

    functionwrapWithCancel(fn) {
       return (data) => {
           if (current === COUNTER) {
               returnfn(data);
           } else {
               returnPromise.reject('cancelled');
           }
        }
    }
}
复制代码

2.使用shouldComponentUpdate或者pureComponent优化

1). 父组件更新时,用shouldComponentUpdate拦截子组件的不必要的render。返回false时,componentWillUpdate(),render()和componentDidUpdate()都不会被调用,即该组件不会更新。当父组件返回true时,整个过程会像叶子节点传递,即叶子节点A与B都会被要求执行更新的生命周期,如果A的shouldComponentUpdate对比其范围内的props和state没有变化而返回false,B返回true,那么只有B更新,从而实现有效的渲染拦截。同时,shouldComponentUpdate内部的判断需高效且正确,如果内部判断开销大于virtual DOM的对比更新的开销,就并没有有效的实现优化;对比中涉及到深浅拷贝的问题也需注意,以保证正确性。
shouldComponentUpdate(newProps, newState) {
        const oldProps = this.props
       if (oldProps.data === newProps.data)
        {
            return false
        }
        return true
    }
复制代码

实际修改

  • 将庞大的父组件抽离成多个子组件,使用shouldComponentUpdate或优化更新效率并减少不必要重绘。

  • 优化已有的shouldComponentUpdate,去除不必要的判断以及未维护的错误判断。

  • 注意表单提交时的校验状态容易被shouldComponentUpdate返回false处理而忽视。

2). pureComponent是通过浅对比props和state来判定是否更新(数组、对象、函数为引用类型,仅值更改时并不会触发更新)。考虑到浅对比的开销,经常改变的组件并不适用于pureComponent,pureComponent更多用于仅用来展示的组件。

猜你喜欢

转载自juejin.im/post/7109106017669611534