欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

React中setState学习总结

程序员文章站 2023-09-29 00:00:52
react中setState方法到底是异步还是同步,其实这个是分在什么条件下是异步或者同步。 1.先来回顾一下react组件中改变state的几种方式: import React, { Component } from 'react' class Index extends Component { ......

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函数中获取