JS每日一题: 如何理解react中setState?

Posted JS每日一题

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS每日一题: 如何理解react中setState?相关的知识,希望对你有一定的参考价值。

20190306期

如何理解react中setState?

先来看看其定义

setState(object nextState[, function callback])
合并当前state与nextSate,触发UI更新的主要方法,支持可选的回调函数,回调在setState执行完毕并且组件重新渲染完成之后调用

在了解其基本概念后,我们来简单梳理一下,setState是如何做到的

开始之前我们先看一段代码

 
   
   
 
  1. constructor() {

  2. super();

  3. this.state = {

  4. val: 0

  5. };

  6. }

  7. componentDidMount() {

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

  9. console.log(this.state.val); // 第 1 次 log


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

  11. console.log(this.state.val); // 第 2 次 log


  12. setTimeout(() => {

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

  14. console.log(this.state.val); // 第 3 次 log


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

  16. console.log(this.state.val); // 第 4 次 log

  17. }, 0);

  18. }

四次log的值为0,0,2,3, 答案不重要,为什么才重要

 
   
   
 
  1. // 源码位置 https://github.com/facebook/react/blob/35962a00084382b49d1f9e3bd36612925f360e5b/src/renderers/shared/reconciler/ReactUpdates.js#L199

  2. // 篇幅原因我们只取核心代码


  3. function enqueueUpdate(component) {

  4. ensureInjected();


  5. // Various parts of our code (such as ReactCompositeComponent's

  6. // _renderValidatedComponent) assume that calls to render aren't nested;

  7. // verify that that's the case. (This is called by each top-level update

  8. // function, like setProps, setState, forceUpdate, etc.; creation and

  9. // destruction of top-level components is guarded in ReactMount.)


  10. if (!batchingStrategy.isBatchingUpdates) {

  11. // 若 isBatchingUpdates 为 false, 先不管这个 batchingStrategy, 并将当成batchingStrategy 状态置为true

  12. batchingStrategy.batchedUpdates(enqueueUpdate, component);

  13. return;

  14. }


  15. // 若 isBatchingUpdates 为 true,则把当前组件放入 dirtyComponents 数组中

  16. dirtyComponents.push(component);

  17. }


  18. // batchingStrategy 定义

  19. var batchingStrategy = {

  20. // 这个标志来标记是否处于一次 batchupdates 中

  21. isBatchingUpdates: false,


  22. batchedUpdates: function(callback, a, b, c, d, e) {

  23. //

  24. batchingStrategy.isBatchingUpdates = true;


  25. transaction.perform(callback, null, a, b, c, d, e);

  26. }

  27. }

所以为什么最上面示例代码的执行结果是0,0,2,3,是因为两次直接执行的 setState 和在 setTimeout 中的 setState 的调用栈不一样。前两次执行 setState 的时候,此时正处于一次 batchupdates,所以并不会立即更新,而是暂存

setTimeout中执行setState时,batchingStrategy 的 isBatchingUpdates 标志位是 false,也就导致了新的 state 马上生效,没有走到 dirtyComponents 分支。也就是,setTimeout 中第一次 setState 时,this.state.val 为 1,而 setState 完成后打印时 this.state.val 变成了 2。第二次 setState 同理

回过头我们再来看一下前面的代码

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

  2. console.log(this.state.val); // 存入dirtyComponents


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

  4. console.log(this.state.val); // 存入dirtyComponents


  5. setTimeout(() => {

  6. this.setState({val: this.state.val + 1}); // 这里为 this.setState({val: 1 + 1}),立即更新所以后面this.state.val值为2

  7. console.log(this.state.val); // 2


  8. this.setState({val: this.state.val + 1}); // 同理 2 + 1

  9. console.log(this.state.val); // 3

  10. }, 0);

总结

  • setState是否立即更新与调用栈有关

  • 通过isBatchingUpdates字段来判断组件是否处于一次batchupdates中

  • 需要同步的逻辑最好写在回调函数中


最近答题



基友噢如果喜欢,可以分享给好基友噢如果喜欢,可以分享给好基友噢


关注「JS每日一题」,参与答题


以上是关于JS每日一题: 如何理解react中setState?的主要内容,如果未能解决你的问题,请参考以下文章

JS每日一题: react的生命周期有哪些?有什么需要注意的地方?

JS每日一题: react中props和state的区别?

JS每日一题: react中类组件和函数式组件中有什么不同?

从源码的角度再看 React JS 中的 setState

JS每日一题: vue中keepalive怎么理解?

爱创课堂每日一题第三十五天- 说说你对闭包的理解?