Skip to content

react 学习 --- 自己写一个react 5.setState #32

@p2227

Description

@p2227

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调用栈,如图

image
这个调用栈是官方一个例子的,点击某个按钮,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

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

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions