【React】setState

//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 完成了两项工作:

  1. 更新state对象
  2. 驱动组件渲染,引发componentDidUpdate、render等函数调用

setState有两种使用方式:

  1. setState(updater,callback)
    第一个参数,updater,是函数,用来返回新的state对象;
    第二个参数,callback,是回调函数,state改变且渲染完成后callback会被调用。
    updater有两个参数:state和props。
    state 是 最新state(可能不太准确); props 是 从父组件传递过来的props。
  2. 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时 才会更新,属异步更新。
多次调用setStatesetState(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 更新的顺序?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值