随着项目的推进,页面组件越来越多,越来越细。当我们在父组件setState
时,可能都会导致若干子组件进行无效的render
。因此解决这个问题是我们学习的目的。
shouldComponentUpdate做了什么?
使用shouldComponentUpdate
可以让React
知道当前状态或属性的改变是否不影响组件的输出,默认返回ture
,返回false
时不会重写render
,而且该方法并不会在初始化渲染或当使用forceUpdate
时被调用,我们要做的只是这样:
shouldComponentUpdate(nextProps, nextState) {
return this.props.someData === nextProps.someData
}
复制代码
当时我们每次都要写如上的代码是不是很烦,因此React
为我们提供了PureComponent
PureComponent
PureComponent
与Component
几乎完全相同,但PureComponent
通过props
和state
的浅对比来实现 shouldComponentUpate
。如果对象包含复杂的数据结构,它可能会因深层的数据不一致而产生错误的否定判断(表现为对象深层的数据已改变视图却没有更新)
import { Component, PureComponent } from 'react'
class Parent extends Component {
state = {
title: '我是改变的内容',
name: '张三'
}
handleChangeTitle() {
this.setState({ title: '我已经改变' })
}
handleChangeName() {
this.setState({ name: '李四' })
}
render() {
return (
<>
<div onClick={this.handleChangeTitle.bind(this)}>{this.state.title}</div>
<div onClick={this.handleChangeName.bind(this)}>改变children的值</div>
<Child name={this.state.name} />
</>
)
}
}
class Child extends PureComponent {
render() {
console.log('child is render....')
return (
<div>我是子组件的名称:{this.props.name}</div>
)
}
}
复制代码
当触发handleChangeTitle
方法时,render
方法并没有被触发。当触发handleChangeName
方法时,render
方法被触发,完美,但是如果传给Child
的props
不是String
, Number
等这种基本类型,而是类似于Object
复杂类型呢?
import { Component, PureComponent } from 'react'
class Parent extends Component {
state = {
title: '我是改变的内容',
user: { name: '张三' }
}
handleChangeTitle() {
this.setState({ title: '我已经改变' })
}
handleChangeName() {
let { user } = this.state
user.name = '李四'
this.setState({ user })
}
render() {
return (
<>
<div onClick={this.handleChangeTitle.bind(this)}>{this.state.title}</div>
<div onClick={this.handleChangeName.bind(this)}>改变children的值</div>
<Child name={this.state.name} />
</>
)
}
}
class Child extends PureComponent {
render() {
console.log('child is render....')
return (
<div>我是子组件的名称:{this.props.user.name}</div>
)
}
}
复制代码
这个时候,我们发现触发handleChangeName
时,render并没有触发,界面也没有渲染,why?
这是因为state中user对象的引用并没有改变。有人说,我们在handleChangeName
改变user的引用,然后PureComponent判断不就正确了吗?
this.setState({ user: { name: '李四' } })
复制代码
我们工作中,大部分传入的对象可能是这样的user: { name: '张三', age: 26, sex: '南', work: '码畜', ... }
,这个时候你想改变引用就不太合适了。那我们有啥解决方案呢?
immutable.js
immutable是一种持久化数据。一旦被创建就不会被更改。修改immutable对象的时候,将返回新的immutable,且原数据不会改变。immutable数据实现了结构共享:只会影响你改变的节点以及他的父节点,其他节点共享,从而达到了节省性能的目的。
import { Component, PureComponent } from 'react'
import { fromJS } from 'immutable'
class Parent extends Component {
state = {
title: '我是改变的内容',
user: fromJS({ name: '张三' })
}
handleChangeTitle() {
this.setState({ title: '我已经改变' })
}
handleChangeName() {
let { user } = this.state
user = user.set('name', '李四')
this.setState({ user })
}
render() {
return (
<>
<div onClick={this.handleChangeTitle.bind(this)}>{this.state.title}</div>
<div onClick={this.handleChangeName.bind(this)}>改变children的值</div>
<Child name={this.state.name} />
</>
)
}
}
class Child extends PureComponent {
render() {
console.log('child is render....')
const user = this.props.user.toJS()
return (
<>
<div>我是子组件的名称:{this.props.user.get('name')}</div>
<div>我是子组件的名称:{user.name}</div>
</>
)
}
}
复制代码
happy hacking
相关链接:
immutable: juejin.cn/post/697679…