0

0

总结React中的setState

angryTom

angryTom

发布时间:2019-12-19 17:10:56

|

3187人浏览过

|

来源于博客园

转载

总结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 (            
        <p>
                <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>
            </p>        )
    }
}
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 (            
        <p>
                <h1>currentState:{this.state.count}</h1>
                <button onClick={this.update1}>测试1</button>
                <button onClick={this.update2}>测试2</button>
            </p>        )
    }
}
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 (            
        <p>
                <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>
            </p>        )
    }
}
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 (            
        <p>
                <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>
            </p>        )
    }
}
export default Index;

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

在setState()的callback回调函数中

ChatDOC
ChatDOC

ChatDOC是一款基于chatgpt的文件阅读助手,可以快速从pdf中提取、定位和总结信息

下载

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 (            <p>
                <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>
            </p>        )
    }
}
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函数中获取

本文来自 js教程 栏目,欢迎学习!  

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

530

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

534

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

718

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5996

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

492

2023.09.01

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

219

2023.09.04

Js中concat和push的区别
Js中concat和push的区别

Js中concat和push的区别:1、concat用于将两个或多个数组合并成一个新数组,并返回这个新数组,而push用于向数组的末尾添加一个或多个元素,并返回修改后的数组的新长度;2、concat不会修改原始数组,是创建新的数组,而push会修改原数组,将新元素添加到原数组的末尾等等。本专题为大家提供concat和push相关的文章、下载、课程内容,供大家免费下载体验。

240

2023.09.14

js截取字符串的方法介绍
js截取字符串的方法介绍

JavaScript字符串截取方法,包括substring、slice、substr、charAt和split方法。这些方法可以根据具体需求,灵活地截取字符串的不同部分。在实际开发中,根据具体情况选择合适的方法进行字符串截取,能够提高代码的效率和可读性 。

298

2023.09.21

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

4

2026.03.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 5.8万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1万人学习

React核心原理新老生命周期精讲
React核心原理新老生命周期精讲

共12课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号