shouldComponentUpdate 作用
官方文档:https://react.docschina.org/docs/optimizing-performance.html
使用方式:
class Hello extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
if (nextProps.greeting !== this.props.greeting) return true
if (nextState.name !== this.state.name) return true
return false
}
state = {
name: 'Hello Class Component'
}
handleClick () {
this.setState({
name: 'Update - ' + this.state.name
})
}
render() {
console.log('Hello render')
return (
<>
<h1>{this.props.greeting}</h1>
<h2>{this.state.name}</h2>
<button onClick={() => this.handleClick()}>Update State Name</button>
</>
)
}
}
该钩子函数会在props
或者state
更新之后回调,传递两个参数为:更新后的props
、更新后的state
返回一个boolean
:
true
:当前组件及其子组件执行渲染逻辑false
:该组件及其子组件都不需要重新计算渲染
React.PureComponent 纯组件
类组件继承React.PureComponent
时,就相当于以上添加了shouldComponentUpdate
钩子函数的渲染优化
需要注意的是,该函数执行的比较是浅比较(也应该要是浅比较,深度比较太消耗性能),所以某些情况的赋值逻辑需要注意
示例:
import React from "react";
class HobbiesList extends React.PureComponent {
componentDidUpdate() {
console.log('HobbiesList componentDidUpdate')
}
render () {
return (
<>
<ul>
{this.props.hobbies.map(h => <li key={h.id}>{h.name}</li>)}
</ul>
</>
)
}
}
export default class Home extends React.Component {
constructor (props) {
super(props)
this.state = {
currentId: 2,
hobbies: [
{id: 0, name: '吃饭'},
{id: 1, name: '睡觉'},
{id: 2, name: '打王者'},
],
inputVal: '',
}
this.handleInput = this.handleInput.bind(this)
this.addHobby = this.addHobby.bind(this)
}
handleInput (e) {
this.setState({
inputVal: e.target.value
})
}
addHobby () {
const hobbies = this.state.hobbies
const newID = this.state.currentId + 1
const newName = this.state.inputVal
hobbies.push({
name: newName,
id: newID,
})
this.setState({
hobbies,
currentId: newID,
})
}
render () {
return (
<>
<input value={this.state.inputVal} onInput={this.handleInput} />
<button onClick={this.addHobby}>添加爱好</button>
<HobbiesList hobbies={this.state.hobbies} />
</>
)
}
}
代码说明:
HobbiesList
是用户渲染爱好列表数据的组件,接收Home
组件传递的hobbies
属性作为数据源;Home
组件中可以向hobbies
添加数据,修改hobbies
的状态props
变化HobbiesList
重新渲染
如果HobbiesList
继承的是React.Component
,那么,当父级组件有某一个它不需要的状态更新了了,比如Home
– state
中的currentId
,该属性仅在Home
组件中使用,并没有传递给HobbiesList
,但是,当currentId
单独更新的时候,所有的组件还是会执行一次render
函数、componentDidUpdate
等钩子函数,非常消耗性能
说回代码执行情况,当点击【添加爱好】按钮时,会执行以下的逻辑:
addHobby () {
const hobbies = this.state.hobbies
const newID = this.state.currentId + 1
const newName = this.state.inputVal
hobbies.push({
name: newName,
id: newID,
})
this.setState({
hobbies,
currentId: newID,
inputVal: ''
})
}
但是,HobbiesList
组件并不会像想象之中那样更新
因为,Home
中setState()
方法更新的hobbies
数组还是原来的地址,而HobbiesList
继承了纯组件,会在shouldComponentUpdate
钩子函数中进行props
的浅比较,当发现数组(或者对象)的引用值地址一致,就会直接返回false
,也就不会刷新组件了
所以,应该在父级更新状态时调整一下:
addHobby () {
const hobbies = this.state.hobbies
const newID = this.state.currentId + 1
const newName = this.state.inputVal
this.setState({
hobbies: [...hobbies, {
name: newName,
id: newID,
}],
currentId: newID,
inputVal: '',
})
}
使用扩展运算符,并使用了一个新数组设置了状态,子组件就能够更新了
小结
shouldComponentUpdate
可以用于性能优化,通过返回一个boolean
值,指导组件是否重新渲染。但是,也仅用于性能优化,不要特地阻止组件刷新,否则会导致意外的 bug- 类组件可以继承
React.PureComponent
纯组件,可以省下shouldComponentUpdate
钩子函数的编写,进行的是浅比较,需要注意状态更新的赋值方式