组件性能优化方式、虚拟DOM和diff算法
一、组件更新数据
三种组件更新的情况:
- setState() 是
异步
更新数据结构
注意:
使用setState() 方法时,后面的setState() 不要依赖于前面的setState()
可以多次调用setState() ,但只会触发一次重新渲染
this.state = {count:1}
this.setState({
count:this.state.count + 1 //1+1
})
this.setState({
count:this.state.count + 1 //1+1
})
console.log(this.state.count); //1
所有使用setState() 方法更新数据,一次调用就可
- forceUpdate 方法
强制
更新数据 - props 值发生变化更新数据
当组件进行嵌套时,更新了其中的某一个组件后,其他组件的更新方式?
结果:如上图所示,当组件2进行更新时,不仅会更新自己,也会更新后代组件。但是不会更新父组件和兄弟组件
二、组件性能优化
1、减轻 state
目标: 降低页面更新的频率 (只要state中数据发生改变,页面就会重载)
方式: 不用做渲染的数据不要放在state中
,比如定时器 id,直接挂载到this上即可
class App extends React.Component {
// 定义鼠标的xy坐标
state = {
stu:{
name:'王俊凯',
age:18
},
teacher:{
name:'大张伟',
age:30
}
}
//不用渲染到页面上的数据直接挂载到 this 上既可
componentDidMount () {
this.timeId = setInterval(()=>{},200)
}
componentWillUnmount(){
clearInterval(this.timeId)
}
}
2、避免不必要的渲染
问题:组件更新机制中父组件更新会导致子组件随之更新,而子组件没有任何变化时也会被重新渲染,会造成不必要的系统性能浪费
解决方法:使用钩子函数 shouldComponentUpdate(nextProps,nextState)
来判断组件是否应该更新
执行机制: 在执行 render 渲染页面前会先调用 shouldComponentUpdate 来判断是否需要进行渲染,如果返回值为true则进行渲染,反之则不渲染 (shouldComponentUpdate --> render)
class App extends React.Component {
// 参数1: 最新 props 的值
// 参数2: 最新 state 的状态
shouldComponentUpdate(nextProps,nextState){
return true/false // 返回值: 返回true则更新,返回false则不更新
}
render () {...}
}
2.1 利用state阻止不必要的更新
在 shouldComponentUpdate 方法中可以使用两个数据
- nextState: state更新后的值
- this.state: 未更新之前的值
判断更新后的值和更新前的值是否发生变化即可
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state = {
number:0
}
handleClick=()=>{
this.setState(()=>{
return{
number:Math.floor(Math.random() * 3)
}
})
}
shouldComponentUpdate(nextProps,nextState){
console.log("最新状态:",nextState, ",当前状态",this.state);
if(nextState.number === this.state.number){
return false;
}
return true;
}
render(){
console.log('render')
return(
<div>
<h1>随机数:{this.state.number}</h1>
<button onClick = {this.handleClick}>重新生成</button>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
效果图:从结果可以看出,当下一个值和当前值相同的时候,只更新状态,而不输出render,也就是阻止了不必要的输出
2.2 利用 props 阻止不必要的更新
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state = {
number:0
}
handleClick=()=>{
this.setState(()=>{
return{
number:Math.floor(Math.random() * 3)
}
})
}
render(){
return(
<div>
<NumberBox number={this.state.number}></NumberBox>
<button onClick = {this.handleClick}>重新生成</button>
</div>
)
}
}
class NumberBox extends React.Component{
shouldComponentUpdate(nextProps){
console.log("最新props:",nextProps, ",当前props",this.props);
if(nextProps.number === this.props.number){
return false;
}
return true
}
render(){
console.log('子组件中的render');
return <h1>随机数:{this.props.number}</h1>
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
state 和 props 状态比较:
当状态是组件自己的属性,可以使用nextState 进行比较,当状态是接收的,则可以选择 nextProps 比较数值是否发生变化
3、纯组件
纯组件: React.PureComponet 与 React.Component 功能相似,也可以用来实现类组件
作用: 纯组件内部自动实现了 shouldComponentUpdate 钩子函数
原理: 纯组件内部会自动比对前后两次 props 和 state 的值来决定是否需要重新渲染
class App extends React.PureComponent {
render () {
return (
<div>纯组件</div>
)
}
}
案例:使用纯组件完成随机数案例
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.PureComponent {
state = {
count: 0
}
updateApp = () => {
this.setState({
count: Math.floor(Math.random() * 3)
})
}
render () {
return (
<div>
<div>{this.state.count}</div>
<div><button onClick={this.updateApp}>随机更新</button></div>
</div>
)
}
componentDidUpdate () {
console.log('App-componentDidUpdate')
}
}
ReactDOM.render(<App/>, document.getElementById('root'))