• React中setState学习总结


    react中setState方法到底是异步还是同步,其实这个是分在什么条件下是异步或者同步。

    1.先来回顾一下react组件中改变state的几种方式:

    import React, { Component } from 'react'
    
    class Index extends Component {
        state={
            count:1
        }
        test1 = () => {
            // 通过回调函数的形式
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('test1 setState()之后',this.state.count);
        }
        test2 = () => {
            // 通过对象的方式(注意:此方法多次设置会合并且只调用一次!)
            this.setState({
                count:this.state.count+1
            });
            console.log('test2 setState()之后',this.state.count);
        }
        test3 = () => {
            // 不能直接修改state的值,此方法强烈不建议!!!因为不会触发重新render
            this.state.count += 1;
        }
        test4 = () => {
            // 在第二个callback拿到更新后的state
            this.setState({
                count:this.state.count+1
            },()=>{// 在状态更新且页面更新(render)后执行
                console.log('test4 setState()之后',this.state.count);
            });
        }
        render() {
            console.log('render');
            return (
                <div>
                    <h1>currentState:{this.state.count}</h1>
                    <button onClick={this.test1}>测试1</button>
                    <button onClick={this.test2}>测试2</button>
                    <button onClick={this.test3} style={{color:'red'}}>测试3</button>
                    <button onClick={this.test4}>测试4</button>
                </div>
            )
        }
    }
    export default Index;

    2.setState()更新状态是异步还是同步:

    需要判断执行setState的位置

    同步:在react控制的回调函数中:生命周期钩子/react事件监听回调

    import React, { Component } from 'react'
    
    class Index extends Component {
        state={
            count:1
        }
        /* 
        react事件监听回调中,setState()是异步状态
        */
        update1 = () => {
            console.log('update1 setState()之前',this.state.count);
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('update1 setState()之后',this.state.count);
        }
        /* 
        react生命周期钩子中,setState()是异步更新状态
        */
        componentDidMount() {
            console.log('componentDidMount setState()之前',this.state.count);
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('componentDidMount setState()之后',this.state.count);
        }
        
        render() {
            console.log('render');
            return (
                <div>
                    <h1>currentState:{this.state.count}</h1>
                    <button onClick={this.update1}>测试1</button>
                    <button onClick={this.update2}>测试2</button>
                </div>
            )
        }
    }
    export default Index;

    异步:非react控制的异步回调函数中:定时器回调/原生事件监听回调/Promise

    import React, { Component } from 'react'
    
    class Index extends Component {
        state={
            count:1
        }
        /* 
        定时器回调
        */
        update1 = () => {
            setTimeout(()=>{
                console.log('setTimeout setState()之前',this.state.count);//1
                this.setState((state,props)=>({
                    count:state.count+1
                }));
                console.log('setTimeout setState()之后',this.state.count);//2
            });
        }
        /* 
        原生事件回调
        */
        update2 = () => {
            const h1 = this.refs.count;
            h1.onclick = () => {
                console.log('onClick setState()之前',this.state.count);//1
                this.setState((state,props)=>({
                    count:state.count+1
                }));
                console.log('onClick setState()之后',this.state.count);//2
            }
        }
        /* 
        Promise回调
        */
        update3 = () => {
            Promise.resolve().then(value=>{
                console.log('Promise setState()之前',this.state.count);//1
                this.setState((state,props)=>({
                    count:state.count+1
                }));
                console.log('Promise setState()之后',this.state.count);//2
            });
        }
        
        render() {
            console.log('render');
            return (
                <div>
                    <h1 ref='count'>currentState:{this.state.count}</h1>
                    <button onClick={this.update1}>测试1</button>
                    <button onClick={this.update2}>测试2</button>
                    <button onClick={this.update3}>测试3</button>
                </div>
            )
        }
    }
    export default Index;

    3.setState()多次调用的问题:

    异步的setState()

    (1)多次调用,处理方法:

    setState({}):合并更新一次状态,只调用一次render()更新界面,多次调用会合并为一个,后面的值会覆盖前面的值。

    setState(fn):更新多次状态,只调用一次render()更新界面,多次调用不会合并为一个,后面的值会覆盖前面的值。

    import React, { Component } from 'react'
    
    class Index extends Component {
        state={
            count:1
        }
        update1 = () => {
            console.log('update1 setState()之前',this.state.count);
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('update1 setState()之后',this.state.count);
            console.log('update1 setState()之前2',this.state.count);
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('update1 setState()之后2',this.state.count);
        }
        update2 = () => {
            console.log('update2 setState()之前',this.state.count);
            this.setState({
                count:this.state.count+1
            });
            console.log('update2 setState()之后',this.state.count);
            console.log('update2 setState()之前2',this.state.count);
            this.setState({
                count:this.state.count+1
            });
            console.log('update2 setState()之后2',this.state.count);
        }
        update3 = () => {
            console.log('update3 setState()之前',this.state.count);
            this.setState({
                count:this.state.count+1
            });
            console.log('update3 setState()之后',this.state.count);
            console.log('update3 setState()之前2',this.state.count);
            this.setState((state,props)=>({
                count:state.count+1
            }));// 这里需要注意setState传参为函数模式时,state会确保拿到的是最新的值
            console.log('update3 setState()之后2',this.state.count);
        }
        update4 = () => {
            console.log('update4 setState()之前',this.state.count);
            this.setState((state,props)=>({
                count:state.count+1
            }));
            console.log('update4 setState()之后',this.state.count);
            console.log('update4 setState()之前2',this.state.count);
            this.setState({
                count:this.state.count+1
            });// 这里需要注意的是如果setState传参为对象且在最后,那么会与之前的setState合并
            console.log('update4 setState()之后2',this.state.count);
        }
        render() {
            console.log('render');
            return (
                <div>
                    <h1>currentState:{this.state.count}</h1>
                    <button onClick={this.update1}>测试1</button>
                    <button onClick={this.update2}>测试2</button>
                    <button onClick={this.update3}>测试3</button>
                    <button onClick={this.update4}>测试4</button>
                </div>
            )
        }
    }
    export default Index;

    (2)如何得到setState异步更新后的状态数据:

    在setState()的callback回调函数中

    4.react中常见的setState面试题(setState执行顺序)

    import React, { Component } from 'react'
    // setState执行顺序
    class Index extends Component {
        state={
            count:0
        }
        componentDidMount() {
            this.setState({count:this.state.count+1});
            this.setState({count:this.state.count+1});
            console.log(this.state.count);// 2 => 0
            this.setState(state=>({count:state.count+1}));
            this.setState(state=>({count:state.count+1}));
            console.log(this.state.count);// 3 => 0
            setTimeout(() => {
                this.setState({count:this.state.count+1});
                console.log('setTimeout',this.state.count);// 10 => 6
                this.setState({count:this.state.count+1});
                console.log('setTimeout',this.state.count);// 12 => 7
            });
            Promise.resolve().then(value=>{
                this.setState({count:this.state.count+1});
                console.log('Promise',this.state.count);// 6 => 4
                this.setState({count:this.state.count+1});
                console.log('Promise',this.state.count);// 8 => 5
            });
        }
        render() {
            console.log('render',this.state.count);// 1 => 0  // 4 => 3 // 5 => 4 // 7 => 5 // 9 => 6 // 11 => 7
            return (
                <div>
                    <h1>currentState:{this.state.count}</h1>
                    <button onClick={this.update1}>测试1</button>
                    <button onClick={this.update2}>测试2</button>
                    <button onClick={this.update3}>测试3</button>
                    <button onClick={this.update4}>测试4</button>
                </div>
            )
        }
    }
    export default Index;

    总结:react中setState()更新状态的2种写法

    1)setState(updater,[callback])

    updater:为返回stateChange对象的函数:(state,props)=>stateChange,接收的state和props都保证为最新

    2)setState(stateChange,[callback])

    stateChange为对象,callback是可选的回调函数,在状态更新且界面更新后才执行

    注意:

    对象是函数方式的简写方式

    如果新状态不依赖于原状态,则使用对象方式;

    如果新状态依赖于原状态,则使用函数方式;

    如果需要在setState()后获取最新的状态数据,在第二个callback函数中获取

  • 相关阅读:
    Python实现TCP服务端的并发
    python程序中的线程操作
    jmeter命令行执行脚本_动态参数设置
    App客户端性能测试点总结
    App功能测试点总结
    jmeter中生成UUID作为唯一标识符
    Python Unittest进行接口测试的简单示例
    jmeter接口测试中的用例数据分离
    博客园看板娘的简单添加
    (转)后端服务性能压测实践
  • 原文地址:https://www.cnblogs.com/abc-x/p/12051364.html
Copyright © 2020-2023  润新知