关于React的性能优化
一、React的diff算法
1.1 React更新机制
首先看一下Raect的渲染流程:
再看一下React的更新流程:
1.2 React更新流程
React在state或props发生改变时,调用render函数,渲染一颗新的虚拟DOM树;
React需要基于这两颗不同的树之间的差异来判别如何有效的更新UI:
- 同层之间相互比较,不会跨节点比较;
- 不同类型的节点,产生不同的树结构(如果以div标签为根的树改为了p标签,那div的所有子元素都重新渲染,产生p为根的树);
- 开发中,可以通过key来指定哪些节点在不同的渲染下保持稳定;
如图所示,只会进行同层之间的比较
tip:为什么不建议使用index作为key?
在列表渲染时,使用index作为key是没有性能提升的,因为diff算法在对key进行比较时,如果key为index索引,那么在列表中间插入一个值时,后面的所有index都会发生改变,原来元素的index和新的元素的index自然就会不同,即使他们是同一个元素,但是key为index,index不一致就会进行重渲染而不是移动原来的元素到新的位置。
二、SCU
在render函数执行时存在这么一个问题:
每当调用setState进行数据更新时,就会执行render函数来重新渲染我们的DOM结构,如果我们只更新了父组件中的数据,但是子组件内依赖的props并没有发生改变,只要调用render,就都会重新渲染,即使子组件的数据没有发生改变,这就会导致性能低下。
shouldComponentUpdate生命周期
React提供了一个生命周期方法 shouldComponentUpdate(简称为SCU),这个方法接受参数,并且要有返回值:
该方法有两个参数:
- 参数一:nextProps:props修改之后新的props属性;
- 参数二:nextState:state修改之后新的state属性。
这个生命周期函数可以决定render函数是否执行,返回值是一个boolean类型:
- 如果它返回的是一个true,就执行render;
- 如果返回的是false,那render不会执行,就不会重新渲染DOM。
- 默认返回的是true,也就是说只要state发生改变,就会调用render函数来重新渲染DOM
PrueComponent
但是如果每次都在组件内部使用 shouldComponentUpdate, 那么开发起来真的是好麻烦啊;
- 而使用shouldComponentUpdate的目的不外乎是当state中的数据发生改变时,来决定 shouldComponentUpdate 返回的是true还是false,来决定组件要不要重新渲染。
- React已经提供了一个方法实现这点,只需要将class组件继承自 PureComponent类就好了。
demo如下:App组件有Home和Banner两个子组件,Home有App传递的props,Banner没有porps
import React, { PureComponent } from 'react'
import Home from './Home'
import Banner from './Banner'
export class App extends PureComponent {
constructor() {
super()
this.state = {
message: "Hello World"
}
}
chanegText() {
this.setState({
message: "你好,世界"
})
}
render() {
console.log("App render")
const { message } = this.state
return (
<div>
<h2>{message}</h2>
<button onClick={e => this.chanegText()}>修改文本</button>
<Home message={message} />
<Banner />
</div>
)
}
}
export default App
import React, { PureComponent } from 'react'
export class Home extends PureComponent {
constructor(props) {
super(props)
}
render() {
console.log("Home render")
const { message } = this.props
return (
<div>
<h2>Home</h2>
<div>{message}</div>
</div>
)
}
}
export default Home
import React, { PureComponent } from 'react'
export class Banner extends PureComponent {
constructor() {
super()
}
render() {
console.log("Banner render")
return (
<div>Banner</div>
)
}
}
export default Banner
memo 高阶组件
函数式组件如何实现PrueComponent那样在props没有改变时,不要重新渲染DOM树呢?;
只需要使用高阶组件memo就可以了:
import { memo } from "react"
const PreFile = memo(function() {
return (
<div>
PreFile
</div>
)
})
export default PreFile
React官网:zh-hans.react.dev/reference/r…
三、useSelector的第二个参数shallEqual
转载自:https://juejin.cn/post/7352387578908868660