React前端渲染优化--父组件导致子组件重复渲染的问题

目录

React前端渲染优化--父组件导致子组件重复渲染

说明

一般的优化方式

项目中常见会导致重复渲染的写法以及改进方法

组件重复渲染问题(pureComponent, React.memo, useMemo, useCallback)

render执行会带来两个方面的影响

下面将具体说明这几个都使用场景和解决的问题

React前端渲染优化--父组件导致子组件重复渲染 说明

目前我们所使用 react 版本一般会有以下四种方式触发渲染 render,而其中通过父组件 render 会直接通知子组件也进行 render。

一般的优化方式

鉴于此种情况,如果完全不做控制下,父组件 render, 那么子组件一定会 render。真实 dom 的渲染 react 会在 diff 算法之后合计出最小改动,进行操作。但对于结构复杂页面,自顶向下,只是单纯 diff 也要花费很长的时间来处理 js 任务。再加上我们每个组件的 render 中也会写很多业务、数据处理。

js 为单线程执行,显然,不必要的子组件的 render 会浪费 js 线程资源,复杂任务还会长时间占用线程导致假死状态,也就是页面卡顿,react 底层有 Fiber 来优化任务队列,但无法优化业务代码上的问题。

一般子组件可以通过确认 props 是否发生变化来控制自身是否进行 render,比如 react-mobx 中的 observer 高阶方法或者 React.PureComponet 就是用来做浅层比较进行控制处理。

项目中常见会导致重复渲染的写法以及改进方法

函数导致的渲染重复

箭头函数 props.fn = () => {} 或者 绑定方法 props.fn = this.xxx.bind(this)

这样的写法每次父组件 render 都会新声明一个 function 传递给子组件,会导致 observer 失去比对作用,父组件每次 render 都会使这个组件 render,严重影响性能!

import React from 'react'; import { observer } from 'mobx-react'; // 我们开发中常见的一个被观测组件,例如 ObserverComponent @observer class ObserverComponent extends React.Component { render() { return (<div>ObserverComponent</div>) } } // 例如在父组件 Parent 使用被观测的子组件 ObserverComponent // 请不要给子组件 ObserverComponent 的 props 设置 箭头函数 () => {} 或者 fn.bind(this) 方法 @observer class Parent extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); // 【正确】 } handleChange() {} doSomething = () => {} render() { return ( <ObserverComponent onChange={() => {}} // 【错误】 onChange={this.handleChange.bind(this)} // 【错误】 onChange={this.handleChange} // 【正确】 todo={this.doSomething} // 【正确】 /> ) } }

字面量写法导致的渲染重复

由于字面量的写法{} 和 { pageSizeOptions: ['10'] },每次都会字面量声明一个新的对象传递给列表组件,导致页面重新 render。

toJS() 方法每次也会返回新对象,会导致页面重新渲染

组件重复渲染问题(pureComponent, React.memo, useMemo, useCallback)

在一个组件中, 其state变化会引起render的重新执行, 函数式组件中, 使用setHook更新state也会引起render的重新执行

render执行会带来两个方面的影响

1.当前组件需要重新渲染, 除了那些状态和生命周期初始化被保留的,其余正常的都会重新执行。

2.子组件会重新渲染, 即使其是一个无状态组件

针对上述问题, react给出来解决方案:

pureComponent

React.memo

useMemo

useCallback

下面将具体说明这几个都使用场景和解决的问题

useMemo设计的初衷就是避免重复进行大规模的计算, 它的理想作用对象是当前组件

具体是将当前组件中一个经过很复杂的计算得到的值缓存起来, 当其依赖项不变的时候, 即使组件重新渲染, 也不会重新计算。

通过上述描述也能理解出其缓存的是一个具体的数据(可以和接下来的useCallback区分开)

/* 缓存了一个对象, 只有当count变化时才会重新返回该对象 */ const useInfo = useMemo( () => ({ count: count, name: "name" }), [count] )

针对第二点, 分别有三个解决方案

首先是useCallback, 其语法和useMemo基本一致, 但是其使用场景是父组件定义了一个函数并且将这个函数传递给了子组件, 那么当父组件重新渲染时,生成的会是一个新的函数, 这个时候就可以使用useCallback了,如下:

const Page = (props) => { const [count, setCount] = useState(0); const [name, setName] = useState('Child组件'); return ( <> <ChildMemo name={name} onClick={ useCallback((newName: string) => setName(newName), []) }/> {/* useCallback((newName: string) => setName(newName),[]) */} {/* 这里使用了useCallback优化了传递给子组件的函数,只初始化一次这个函数,下次不产生新的函数 </> ) }

上述是一个简写的形式,意思就是将传递给子组件的这个函数缓存了,其第二个参数就是依赖,当该依赖变化时,将会重新缓存该函数

其余useMemo的区别就在于,其缓存的是函数本身,而useMemo缓存的是函数计算后的值,都会在依赖项变化时重新缓存。

注:虽然其可能对于父组件传递给子组件函数时可能很理想,但实际上其带来的性能损耗也是显而易见的,其使用场景不应该是担心本组件的函数因为本组件重新渲染而重新生成,这样反而起到了反效果,当前组件更新,其重新渲染,内部的函数也重新生成,其性能损耗可以忽略不计,如下图。

使用场景应该是父组件更新导致重新生成的函数又传递给了子组件,导致子组件重新渲染。

接着是pureComponent

它是一个类, 组件继承自它后, 其作为子组件时, 每次父组件更新后, 会浅对比传来的props是否变化, 若没变化, 则子组件不更新。

React.memo

同上条功能类似, 当其作用于函数式组件并且作为子组件时, 每次父组件更新后, 会浅对比传来的props是否变化, 若没变化, 则子组件不更新。

// 子组件暴露时暴露为处理后的组件 import {memo} from 'react' const TeacherModal = (props: any) => { return <div></div> } export default memo(TeacherModal)

上面两个都区别在于, 一个是类, 一个是高阶组件, 前者作用于类后者作用于函数

以上为个人经验,希望能给大家一个参考,也希望大家多多支持易知道(ezd.cc)。

推荐阅读

    3500元超额值学生娱乐结构的优化配置

    3500元超额值学生娱乐结构的优化配置,,作为一个DIY的主流用户领域的学生,每个用户51学生攒机的高峰。因为学生用户没有稳定的收入来源,攒机

    优化PostgreSQL中的批量更新性能

    优化PostgreSQL中的批量更新性能,数据,表格,在Ubuntu 12.04上使用PG 9.1. 我们目前需要24小时才能运行大量UPDATE数据库上的语句,其形式

    512内存的电脑优化|笔记本内存512

    512内存的电脑优化|笔记本内存512,,1. 笔记本内存512够用,因为运行非常流畅,苹果笔记本 16g512的运行内存是16g内存,机身内存是512g内存,运行

    Windows7下固态硬盘的优化技术

    Windows7下固态硬盘的优化技术,,当微软开发Windows Vista时,固态硬盘没有那么热,所以没有进行优化。Windows 7是不同的。微软从一开始就把SS

    记一次服务端系统性能优化

    记一次服务端系统性能优化,在线,设备, 首先简单介绍一下业务场景,物联网设备,关注公众号,免费领取环保袋。12月8号,也就是昨天上午,突然接

    幻灯片放映慢优化可以加快速度

    幻灯片放映慢优化可以加快速度,,用于制作幻灯片的一些技术更复杂,这些幻灯片在一些旧机器上运行缓慢或缓慢。在这种情况下,我们应该如何优化

    电脑cpu调整软件|电脑优化cpu的软件

    电脑cpu调整软件|电脑优化cpu的软件,,1. 电脑优化cpu的软件出现这个问题归根到底是因为你是用的模拟器,而模拟器是比较卡顿的,尤其在配置比

    bios优化设置|bios的优化设置

    bios优化设置|bios的优化设置,,1. bios的优化设置开机按del键,在bios设置菜单中选择loadfall-safe defaults,在弹出的确认提示中按y键即可

    hp超级本envy优化|hp envy bios

    hp超级本envy优化|hp envy bios,,hp超级本envy优化笔记本开机时显示报错码3f0表现为系统卡顿,原因和解决方法如下3、电脑同时开启了多个应