自己写一个 react 5.setState
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论