UI=render(data)
,你负责提供data
,React负责render
。
React的工作就是渲染,就是操作DOM,而且是很有智慧地操作DOM。
组件的state
或props
变化时,React会比对这次虚拟DOM和上次虚拟DOM,然后根据二者的不同,来操作真实DOM。
shouldComponentUpdate
- index.js
import React from 'react';
import ReactDOM from 'react-dom';
import CountDown from "./countDown.js";
ReactDOM.render(
<CountDown initialCount={10}/>,
document.querySelector('#root')
)
- index.css
.btn,.count{
margin-right:5px;
}
- countDown.js
import React from "react";
import "./index.css";
class CountDown extends React.Component{
constructor(props){
super(props);
this.state = {
count:props.initialCount
}
this.handleIncrement = () => {
this.setState(currentState => ({
count:currentState.count+1
}))
}
this.handleDecrement = () => {
this.setState(currentState => ({
count:currentState.count-1
}))
}
this.handleClick = () => {
this.setState(currentState => ({
count:currentState.count
}))
}
}
render(){
console.log("enter render");
return (
<>
<span className="count">{this.state.count}</span>
<button className="btn" onClick={this.handleIncrement}>+</button>
<button className="btn" onClick={this.handleDecrement}>-</button>
<button className="btn" onClick={this.handleClick}>click me</button>
</>
)
}
}
export default CountDown;
点击+时,state.count
加1,进入render
重新渲染;
点击-时,state.count
减1,进入render
重新渲染;
点击click me时,state.count
没变,为啥还要进入render
重新渲染?
这个锅 shouldComponentUpdate
得背!
因为handleClick
里调用setState()
时并没有立即更新state
,而是先问了shouldComponentUpdate
,shouldComponentUpdate
给了肯定的答复后,才往下走继续更新state
、重新render
的。
React里 shouldComponentUpdate
的默认实现是返回true
。
shouldComponentUpdate(nextProps,nextState){
return true
}
那么,我们就会想了,是不是shouldComponentUpdate
给了否定的答案,后面的状态更新、组件渲染就会停止?是的,的确如此。
如果shouldComponentUpdate
始终返回false
,不论点哪个按钮,计数器数值都不会改变。
shouldComponentUpdate(nextProps,nextState){
return false
}
当然,我们肯定不会这么做。我们只是希望点击+时计数器加1,点击-计数器减1,点击click me时,计数器值不变且不浪费时间重新渲染。
所以,添加的shouldComponentUpdate
就像下面这样:
shouldComponentUpdate(nextProps,nextState){
// console.log('this.state.count:',this.state.count,'nextState.count:',nextState.count);
if(nextState.count === this.state.count) return false;
return false
}
shouldComponentUpdate
接受两个参数:nextProps
和nextState
。
nextState
, 本次的state
; this.state
,上次的state
;
nextProps
,本次的props
; this.props
,上次的props
。
React.PureComponent
如果比较的只是字符串、数值、布尔值等基本数据类型,React.PureComponent
也是个不错的方案,这时我们就可以偷懒不写shouldComponentUpdate
了。
import React from "react";
import "./index.css";
// class CountDown extends React.Component{
class CountDown extends React.PureComponent{
constructor(props){
super(props);
this.state = {
count:props.initialCount
}
this.handleIncrement = () => {
this.setState(currentState => ({
count:currentState.count+1
}))
}
this.handleDecrement = () => {
this.setState(currentState => ({
count:currentState.count-1
}))
}
this.handleClick = () => {
this.setState(currentState => ({
count:currentState.count
}))
}
}
render(){
return (
<>
<span className="count">{this.state.count}</span>
<button className="btn" onClick={this.handleIncrement}>+</button>
<button className="btn" onClick={this.handleDecrement}>-</button>
<button className="btn" onClick={this.handleClick}>click me</button>
</>
)
}
}
export default CountDown;
当然,应对 数组、对象等引用类型时,React.PureComponent
无能为力。