侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

总结React中的setState

前端  /  管理员 发布于 7年前   234

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);//1this.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);//1this.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);//1this.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回调函数中

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 => 6this.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 => 4this.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教程 栏目,欢迎学习!

以上就是总结React中的setState的详细内容,更多请关注其它相关文章!


  • 上一条:
    js获取DOM元素的方式总结
    下一条:
    CSS绝对定位详解
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客