//index.js
import React from "react";
import ReactDOM from "react-dom";
import Counter from "./counter.js";
ReactDOM.render(
<Counter caption="计数器"/>,
document.querySelector('#root')
)
//counter.js
import React from "react";
const style = {
marginRight:"5px"
}
class Counter extends React.Component{
constructor(props){
super(props);
this.state = {
count:0
}
this.handleIncrement = () => {
this.setState(
(state,props) => {
console.log(props);
return {
count:state.count+1
}
},
()=>{
console.log("当前计数:",this.state.count);
}
)
}
this.handleDecrement = () => {
this.setState(
{
count:this.state.count-1
},
() => {
console.log("当前计数:",this.state.count)
}
)
}
}
render(){
return (
<>
<h3>{this.props.caption}</h3>
<button style={style} onClick={this.handleIncrement}>+</button>
<button style={style} onClick={this.handleDecrement}>-</button>
<span>{this.state.count}</span>
</>
);
}
}
export default Counter;
setState
完成了两项工作:
- 更新state对象
- 驱动组件渲染,引发componentDidUpdate、render等函数调用
setState
有两种使用方式:
setState(updater,callback)
第一个参数,updater,是函数,用来返回新的state对象;
第二个参数,callback,是回调函数,state改变且渲染完成后callback会被调用。
updater有两个参数:state和props。
state 是 最新state(可能不太准确); props 是 从父组件传递过来的props。setState(stateChange,callback)
第一个参数,stateChange,是一个新的state对象;
第二个参数,callback,是回调函数,state改变且渲染完成后callback会被调用。
setState
并不总会立即更新this.state
,可能同步,也可能异步。
import React from "react";
const style = {
marginRight:"5px"
}
class Counter extends React.Component{
constructor(props){
super(props);
this.state = {
count:0
}
this.handleIncrement = () => {
this.setState((state,props) => ({count:state.count+1}));
this.setState((state,props) => ({count:state.count+1}));
this.setState((state,props) => ({count:state.count+1}));
// this.setState((state,props) => {
// console.log("this.state.count:",this.state.count," ","state.count:",state.count);
// return { count:state.count+1 }
// })
// this.setState((state,props) => {
// console.log("this.state.count:",this.state.count," ","state.count:",state.count);
// return { count:state.count+1 }
// })
// this.setState((state,props) => {
// console.log("this.state.count:",this.state.count," ","state.count:",state.count);
// return { count:state.count+1 }
// })
}
this.handleDecrement = () => {
this.setState({count:this.state.count-1});
this.setState({count:this.state.count-1});
this.setState({count:this.state.count-1});
// this.setState({count:this.state.count-1}); console.log("this.state.count:",this.state.count);
// this.setState({count:this.state.count-1}); console.log("this.state.countt:",this.state.count);
// this.setState({count:this.state.count-1}); console.log("this.state.count:",this.state.count);
}
}
static getDerivedStateFromProps(nextProps,nextState){
console.log("enter getDerivedStateFromProps","nextState:",nextState);
return null;
}
shouldComponentUpdate(nextProps,nextState){
console.log("enter shouldComponentUpdate");
return true;
}
render(){
console.log("enter render");
return (
<>
<h3>{this.props.caption}</h3>
<button style={style} onClick={this.handleIncrement}>+</button>
<button style={style} onClick={this.handleDecrement}>-</button>
<span>{this.state.count}</span>
</>
);
}
}
export default Counter;
本例,调用setState
时,this.state
没有立即更新,到了 调用render
时 才会更新,属异步更新。
多次调用setState
,setState(updater,callback)
、setState(stateChange,callback)
都会有个合并的过程,但合并方式不同,因而最终的this.state.count
不一样。不过,不论以何种方式 setState
,组件都只会渲染一次。
import React from "react";
const style = {
marginRight:"5px"
}
class Counter extends React.Component{
constructor(props){
super(props);
this.state = {
count:0
}
this.handleIncrement = () => {
this.setState(state => ({count:state.count+1}));
console.log("setState in onClick","this.state.count:",this.state.count);
}
this.handleDecrement = () => {
setTimeout(() => {
this.setState(state => ({count:state.count-1}));
console.log("setState in setTimeout","this.state.count:",this.state.count);
})
}
this.handleClickA = () => {
this.setState(state => ({count:state.count+1}));
console.log("setState in EventListener","this.state.count:",this.state.count);
}
this.handleClickB = () => {
new Promise(resolve => {
this.setState(state => ({count:state.count-1}));
resolve(this.state.count);
}).then(count => {
console.log("setState in Promise","this.state.count",count);
})
}
}
componentDidMount(){
document.querySelector('#testA').addEventListener("click",this.handleClickA);
document.querySelector('#testB').addEventListener("click",this.handleClickB);
}
componentWillUnmount(){
document.querySelector('#testA').removeEventListener("click",this.handleClickA);
document.querySelector('#testB').removeEventListener("click",this.handleClickB);
}
render(){
console.log("enter render","this.state.count:",this.state.count);
return (
<>
<h3>{this.props.caption}</h3>
<button style={style} onClick={this.handleIncrement}>+</button>
<button style={style} onClick={this.handleDecrement}>-</button>
<button style={style} id='testA'>+(test)</button>
<button style={style} id='testB'>-(test)</button>
<span>{this.state.count}</span>
</>
);
}
}
export default Counter;
addEventListener
里调用setState
,同步更新了this.state
;
setTimeout
里调用setState
,同步更新了this.state
;
Promise
里调用setState
,同步更新了this.state
;
React事件处理程序的setState
,异步更新了this.state
,这是因为React事件处理程序中的更新 默认会被批量处理。
参考文章
setState:这个API设计到底怎么样
何时以及为什么 setState() 会批量执行?
React 是否保持 state 更新的顺序?