资讯专栏INFORMATION COLUMN

React-setState杂记

yuxue / 3075人阅读

摘要:简单的举下例子如等生命周期以及的事件即为异步更新,这里不显示具体代码。因为只有当父组件后才传给子组件,那么如果要变成同步的,就需要放弃。

前言

在看React的官方文档的时候, 发现了这么一句话,State Updates May Be Asynchronous,于是查询了一波资料, 最后归纳成以下3个问题

setState为什么要异步更新,它是怎么做的?

setState什么时候会异步更新, 什么时候会同步更新?

既然setState需要异步更新, 为什么不让用户可以同步读到state的新值,但更新仍然是异步?

常见场景下的异步更新

以下是官方文档的一个例子, 调用了3次incrementCount方法, 期望this.state.count的值是3, 但最后却是1

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

handleSomething() {
  // Let"s say `this.state.count` starts at 0.
  this.incrementCount();
  this.incrementCount();
  this.incrementCount();
  // When React re-renders the component, `this.state.count` will be 1, but you expected 3.

  // This is because `incrementCount()` function above reads from `this.state.count`,
  // but React doesn"t update `this.state.count` until the component is re-rendered.
  // So `incrementCount()` ends up reading `this.state.count` as 0 every time, and sets it to 1.

  // The fix is described below!
}

那么就可以引出第一个问题

setState为什么要异步更新,它是怎么做的?

深入源码你会发现:(引用程墨老师的setState何时同步更新状态)

在 React 的 setState 函数实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到队列中回头再说,
而 isBatchingUpdates 默认是 false,也就表示 setState 会同步更新 this.state,
但是,有一个函数 batchedUpdates,这个函数会把 isBatchingUpdates 修改为 true,
而当 React 在调用事件处理函数之前就会调用这个 batchedUpdates,造成的后果,就是由 React 控制的事件处理过程 setState 不会同步更新 this.state。

然后我在网上引用了这张图(侵删)

从结论和图都可以得出, setState是一个batching的过程, React官方认为, setState会导致re-rederning, 而re-rederning的代价是昂贵的, 所以他们会尽可能的把多次操作合并成一次提交。以下这段话是Dan在Issue中的回答:

中心意思大概就是:
同步更新setState并re-rendering的话在大部分情况下是无益的, 采用batching会有利于性能的提升, 例如当我们在浏览器插入一个点击事件时,父子组件都调用了setState,在batching的情况下, 我们就不需要re-render两次孩子组件,并且在退出事件之前re-render一次即可。

那么如果我们想立即读取state的值, 其实还有一个方法, 如下代码:
因为当传入的是一个函数时,state读取的是pending队列中state的值

incrementCount() {
  this.setState((state) => {
    // Important: read `state` instead of `this.state` when updating.
    return {count: state.count + 1}
  });
}

handleSomething() {
  // Let"s say `this.state.count` starts at 0.
  this.incrementCount();
  this.incrementCount();
  this.incrementCount();

  // If you read `this.state.count` now, it would still be 0.
  // But when React re-renders the component, it will be 3.
}

当然, 仔细看React文档的话, 可以发现, State Updates May Be Asynchronou里面有一个may的字眼,也就是可能是异步更新, 因而引出第二个问题

setState什么时候会异步更新, 什么时候会同步更新?

其实从第一个问题中我们就知道,React是根据isBatchingUpdates来合并更新的, 那么当调用setState的方法或者函数不是由React控制的话, setState自然就是同步更新了。

简单的举下例子:

如componentDidMount等生命周期以及React的事件即为异步更新,这里不显示具体代码。

如自定义的浏览器事件,setTimeout,setInterval等脱离React控制的方法, 即为同步更新, 如下(引用程墨老师的setState何时同步更新状态)

componentDidMount() {
  document.querySelector("#btn-raw").addEventListener("click", this.onClick);
}
onClick() {
  this.setState({count: this.state.count + 1});
  console.log("# this.state", this.state);
}
// ......
render() {
  console.log("#enter render");
  return (
    
{this.state.count}
) }

有的人也会想能不能React依然合并更新, 但用户可以同步读取this.state的值, 这个问题在React的一个Issue上有提到, 也是我们的第三个问题

既然setState需要异步更新, 为什么不让用户可以同步读到state的新值,但更新仍然是异步?

这个问题可以直接在Dan的回答中得到:

This is because, in the model you proposed, this.state would be flushed immediately but this.props wouldn’t. 
And we can’t immediately flush this.props without re-rendering the parent, which means we would have to give up on batching (which, depending on the case, can degrade the performance very significantly).

大概意思就是说:

如果在应用中,this.state的值是同步,但是this.props却不是同步的。因为props只有当re-rendering父组件后才传给子组件,那么如果要props变成同步的, 就需要放弃batching。 但是batching不能放弃。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101595.html

相关文章

  • 2018.12月问题整理杂记

    摘要:布局如下对于这块,我不是很理解,后发现,注销这个样式,用可以解决。后查阅一些资料,到了原因。 -12.24-:html布局如下: html css javascript vue css: tab{ width: 600px; margin: 0 auto; } .tab-tit{ width: 600px; font-si...

    wudengzan 评论0 收藏0
  • React-Router 杂记

    摘要:三种的区别即对应中的值,如,服务器对任务都返回同一个,具体的路径由浏览器区分,因为浏览器不会发送后面的值给服务器。如果是即变成这样,,所以要对服务器配置不同的返回不同的资源。就是没有的情况,比如。 三种Router的区别 1. HashRouter: 即对应url中的hash值,如xx.com/#/a、xx.com/#/a/b, 服务器对任务url都返回同一个url,具体的路径由浏览器...

    keelii 评论0 收藏0
  • React-flux杂记

    摘要:简介是一种搭建客户端的应用架构,更像是一种模式而不是一个框架。 简介 Flux是一种搭建WEB客户端的应用架构,更像是一种模式而不是一个框架。 特点 单向数据流 showImg(https://segmentfault.com/img/remote/1460000018128072?w=1300&h=708); 与MVC的比较 1.传统的MVC如下所示(是一个双向数...

    王岩威 评论0 收藏0
  • JavaScript 杂记(一)

    摘要:基础简单基础数据类型值得注意的是的值是,表示一个空对象指针,没有指向任何对象。的值是,表示申明变量或对象的属性却未初始化。值是派生自的,所以对他们执行相等测试会返回。字符串单引号和双引号都可以用来表示字符串,只要前后一致即可。 目的 记忆总是会随着时间而淡化,学习了点什么,就记录下点什么。 做点什么,总比不做要好。 基础 简单(基础)数据类型 Number ...

    raise_yang 评论0 收藏0
  • 杂记之关于织梦网站修改的一些操作

    摘要:修改菜单首先,修改,为什么看了就明白了提示信息在里修改最后大多数要修改的内容都在里,希望可以帮助到你,没涉及的那你就再百度一下吧,学艺不精欢迎指正 1.修改菜单首先,修改dede/temples/index2.html + dede/inc/inc_menu.php,为什么?!看了就明白了 2.dede提示信息在dede/sys_data_done.php 里修改 最后大多数要修改的...

    yy13818512006 评论0 收藏0

发表评论

0条评论

yuxue

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<