自己写一个 react 5.setState

发布于 2022-02-20 13:46:54 字数 3339 浏览 1137 评论 0

setState 这个 api 里面做了些啥 ,网上有很多资料,典型的是关于源代码里面的一幅 ASCII 图画

/*
 * <pre>
 *                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | wrapper
 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 * </pre>
 */

和相关的测试用例

  this.setState({val: this.state.val + 1});
    console.log(this.state.val);    

    this.setState({val: this.state.val + 1});
    console.log(this.state.val);    

    setTimeout(() => {
      this.setState({val: this.state.val + 1});
      console.log(this.state.val);  

      this.setState({val: this.state.val + 1});
      console.log(this.state.val); 
    }, 0);
  }

综合上面的资料,我理解setState的运行是这样的

开启一个标识->setState只负责把所有的state推进队列->推进完毕,重置标识,批量更新state

这时候我就疑惑了,我setState内部怎么知道其他的setState完毕了没有(黑人问号)。这时候参考一些迷你react,发现他们都是用浏览器原生的延迟实现
https://github.com/developit/preact/blob/2399c49dad2dd9c932e74bfe56dfd577c2d0cde2/src/util.js#L19

这个是整体设计的思路就不一样,没办法参考,我只能看react本身。不过代码非常庞大,有没有什么快捷的方法呢?有的,看chrome调用栈,如图

这个调用栈是官方一个例子的,点击某个按钮,setState改变toggle状态
https://codepen.io/gaearon/pen/xEmzGg?editors=0010

可以看出来,用户点击事件和setState之间,还有很多重调用,在这些里面调用了batchedUpdates,个人觉得react的合成事件与setState之间有相互配合,也就是说我在写react组件时的传递的点击事件,并不是直接调用了setState的,中间还有包裹函数。于是思路就清晰了,代码实现起来也很快,我觉得最关键的是这一步: https://github.com/p2227/diyReact/blob/ed45e6be54dc95b76f0a755352118eb1ed3ea890/src/stage4-transaction.js#L372

而且上面的测试用例也是跑通过的。

不知道我理解得对不对,欢迎抛砖引玉

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

虐人心

有一天你能到我的心里去,你会看到那里全是你给的伤悲。

0 文章
0 评论
24515 人气
更多

推荐作者

胡图图

文章 0 评论 0

zt006

文章 0 评论 0

z祗昰~

文章 0 评论 0

冰葑

文章 0 评论 0

野の

文章 0 评论 0

天空

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文