setState 同步更新

我们在上文中提及,为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于this.state来计算未来状态。典型的譬如我们希望在从服务端抓取数据并且渲染到界面之后,再隐藏加载进度条或者外部加载提示:

componentDidMount() {

fetch('https://example.com')

.then((res) => res.json())

.then(

(something) => {

this.setState({ something });

StatusBar.setNetworkActivityIndicatorVisible(false);

}

);

}

因为setState函数并不会阻塞等待状态更新完毕,因此setNetworkActivityIndicatorVisible有可能先于数据渲染完毕就执行。我们可以选择在componentWillUpdate与componentDidUpdate这两个生命周期的回调函数中执行setNetworkActivityIndicatorVisible,但是会让代码变得破碎,可读性也不好。实际上在项目开发中我们更频繁遇见此类问题的场景是以某个变量控制元素可见性:

this.setState({showForm : !this.state.showForm});

我们预期的效果是每次事件触发后改变表单的可见性,但是在大型应用程序中如果事件的触发速度快于setState的更新速度,那么我们的值计算完全就是错的。本节就是讨论两种方式来保证setState的同步更新。

完成回调

setState函数的第二个参数允许传入回调函数,在状态更新完毕后进行调用,譬如:

this.setState({

load: !this.state.load,

count: this.state.count + 1

}, () => {

console.log(this.state.count);

console.log('加载完成')

});

这里的回调函数用法相信大家很熟悉,就是JavaScript异步编程相关知识,我们可以引入Promise来封装setState:

setStateAsync(state) {

return new Promise((resolve) => {

this.setState(state, resolve)

});

}

setStateAsync返回的是Promise对象,在调用时我们可以使用Async/Await语法来优化代码风格:

async componentDidMount() {

StatusBar.setNetworkActivityIndicatorVisible(true)

const res = await fetch('https://api.ipify.org?format=json')

const {ip} = await res.json()

await this.setStateAsync({ipAddress: ip})

StatusBar.setNetworkActivityIndicatorVisible(false)

}

这里我们就可以保证在setState渲染完毕之后调用外部状态栏将网络请求状态修改为已结束,整个组件的完整定义为:

class AwesomeProject extends Component {

state = {}

setStateAsync(state) {

...

}

async componentDidMount() {

...

}

render() {

return (

My IP is {this.state.ipAddress || 'Unknown'}

);

}

}

该组件的执行效果如下所示:

传入状态计算函数

除了使用回调函数的方式监听状态更新结果之外,React还允许我们传入某个状态计算函数而不是对象来作为第一个参数。状态计算函数能够为我们提供可信赖的组件的State与Props值,即会自动地将我们的状态更新操作添加到队列中并等待前面的更新完毕后传入最新的状态值:

this.setState(function(prevState, props){

return {showForm: !prevState.showForm}

});

这里我们以简单的计数器为例,我们希望用户点击按钮之后将计数值连加两次,基本的组件为:

class Counter extends React.Component{

constructor(props){

super(props);

this.state = {count : 0}

this.incrementCount = this.incrementCount.bind(this)

}

incrementCount(){

...

}

render(){

return

Increment

{this.state.count}

}

}

直观的写法我们可以连续调用两次setState函数,这边的用法可能看起来有点怪异,不过更多的是为了说明异步更新带来的数据不可预测问题。

incrementCount(){

this.setState({count : this.state.count + 1})

this.setState({count : this.state.count + 1})

}

上述代码的效果是每次点击之后计数值只会加1,实际上第二个setState并没有等待第一个setState执行完毕就开始执行了,因此其依赖的当前计数值完全是错的。我们当然可以使用上文提及的setStateAsync来进行同步控制,不过这里我们使用状态计算函数来保证同步性:

incrementCount(){

this.setState((prevState, props) => ({

count: prevState.count + 1

}));

this.setState((prevState, props) => ({

count: prevState.count + 1

}));

}

这里的第二个setState传入的prevState值就是第一个setState执行完毕之后的计数值,也顺利保证了连续自增两次。

react同步请求_React中setState同步更新策略相关推荐

  1. react http请求_React组件的应用分析

    一.如何创建React组件 方式一:React.createClass 用 React.createClass 构建组件是 React 最传统.也是兼容最好的方法. const Button = Re ...

  2. 7 centos 时钟跟物理机同步_通信网中的同步技术

    同步技术的产生,跟其他技术一样,都是有原因的. 在老久之前的电路交换网络时代,因为电路交换的数据流是恒定的,因此可以很容易地从数据流中恢复出所需要的时钟信息,并保持源和宿之间的同步状态.二是整个报文的 ...

  3. react多个网络请求_react中网络请求的优化!

    react中网络请求的优化! 在页面跳转的时候 我会去检查一下 redux中是否存在我需要的值 如果没有 我再去调用接口 如果有的话 那我就不去发网络请求: 如果上个接口挂掉了, 那么我下个接口就不发 ...

  4. java 同步异步_Java中的同步于异步

    java异步同步应用 所谓异步输入输出机制,是指在进行输入输出处理时,不必等到输入输出处理完毕才返回.所以异步的同义语是非阻塞(None Blocking). 网上有很多网友用很通俗的比喻 把同步和异 ...

  5. 陈潇冰 react权威指南_React中条带化付款的分步指南

    陈潇冰 react权威指南 This is an adapted from several excerpts from Scott Hasbrouck's book, "The Node.j ...

  6. react回调函数_React中的回调中自动绑定ES6类函数

    在使用ES6类的React组件时,您必须遇到这种现象,必须显式绑定类函数,然后将其传递给诸如onClick.例如,采用以下示例. import React from 'react';class MyC ...

  7. react 元素延迟加载_React中的延迟加载路线

    react 元素延迟加载 As developers, when we build apps for users on the internet, it is very important to en ...

  8. react 嵌套渲染_React 中嵌套数组数据如何渲染到前端页面

    现在有后端提供的类似下面这种格式的数据 { status:X, body: [ {year: 2017, month: [December, October, ...]} {year: 2016, m ...

  9. react 条件渲染_React中的条件渲染语法

    react 条件渲染 为什么我们不能使用If-Else以及三元运算符如何提供帮助 (Why We Can't Use If-Else and How the Ternary Operator can ...

最新文章

  1. android中常见的内存泄漏和解决的方法
  2. 粒子滤波 演示与opencv代码
  3. 查询高考成绩2021一分一段表,一分一段表查询2021 如何查询一分一段表
  4. Android之EventBus使用详解
  5. 自己实现多线程的socket,socketserver源码剖析
  6. MSN Messenger终于好使了
  7. 前端学习(520):圣杯布局
  8. vs2015打开EXCEL文档范例及其注意事项!!!
  9. 写不出满分作文怎么办,GPT-3 来帮你
  10. 375 Inscribed Circles and Isosceles Triangles 等腰三角形 内接圆 圆周率PI表示
  11. 路由器NAT负载均衡实验过程详解
  12. 【DIOCP开源项目】实际应用案例
  13. liunx下文件授权可执行权限chmod
  14. 数字相控阵雷达的优势(Benefits of Digital Phased Array Radars)1
  15. unity 反编译 step1 disUnity
  16. 干货!闲鱼上哪些商品抢手?Python 分析后告诉你
  17. 【数学模型】基于Volterra理论的捕食模型
  18. 黑魔法-伪类匹配列表数目实现微信群头像CSS布局的技巧
  19. LeetCode久不久来一题系列之Add Two Numbers
  20. WebGIS学习资源推荐(包含学习路线、软件和数据资源推荐)

热门文章

  1. 1分钟 Zookeeper 快速入门_windows环境
  2. node环境搭建流程
  3. 服务器zip解压php,服务器端解压缩zip的脚本
  4. html中给div设置的属性怎么样才能拿得到_前端基础高频面试题(更新中)
  5. linux下文件颜色说明
  6. mysql行级锁升级_mysql innodb 行级锁升级
  7. 负数比较大小_人教版六下【第一单元】负数比较负数的大小
  8. pgadmin连接服务器失败_增值税发票税控软件:连接服务器失败是否使用离线文件进行更新?...
  9. mysql sum id 5_mysql怎么使用sum()求id字段的和?
  10. 福州3 2五年制计算机专业的学校,福州有哪些五年制大专