JS每日一题: 如何理解react中setState?
Posted JS每日一题
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS每日一题: 如何理解react中setState?相关的知识,希望对你有一定的参考价值。
20190306期
如何理解react中setState?
先来看看其定义
setState(object nextState[, function callback])
合并当前state与nextSate,触发UI更新的主要方法,支持可选的回调函数,回调在setState执行完毕并且组件重新渲染完成之后调用
在了解其基本概念后,我们来简单梳理一下,setState是如何做到的
开始之前我们先看一段代码
constructor() {
super();
this.state = {
val: 0
};
}
componentDidMount() {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 1 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 2 次 log
setTimeout(() => {
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 3 次 log
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 第 4 次 log
}, 0);
}
四次log的值为0,0,2,3, 答案不重要,为什么才重要
// 源码位置 https://github.com/facebook/react/blob/35962a00084382b49d1f9e3bd36612925f360e5b/src/renderers/shared/reconciler/ReactUpdates.js#L199
// 篇幅原因我们只取核心代码
function enqueueUpdate(component) {
ensureInjected();
// Various parts of our code (such as ReactCompositeComponent's
// _renderValidatedComponent) assume that calls to render aren't nested;
// verify that that's the case. (This is called by each top-level update
// function, like setProps, setState, forceUpdate, etc.; creation and
// destruction of top-level components is guarded in ReactMount.)
if (!batchingStrategy.isBatchingUpdates) {
// 若 isBatchingUpdates 为 false, 先不管这个 batchingStrategy, 并将当成batchingStrategy 状态置为true
batchingStrategy.batchedUpdates(enqueueUpdate, component);
return;
}
// 若 isBatchingUpdates 为 true,则把当前组件放入 dirtyComponents 数组中
dirtyComponents.push(component);
}
// batchingStrategy 定义
var batchingStrategy = {
// 这个标志来标记是否处于一次 batchupdates 中
isBatchingUpdates: false,
batchedUpdates: function(callback, a, b, c, d, e) {
//
batchingStrategy.isBatchingUpdates = true;
transaction.perform(callback, null, a, b, c, d, e);
}
}
所以为什么最上面示例代码的执行结果是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 同理
回过头我们再来看一下前面的代码
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 存入dirtyComponents
this.setState({val: this.state.val + 1});
console.log(this.state.val); // 存入dirtyComponents
setTimeout(() => {
this.setState({val: this.state.val + 1}); // 这里为 this.setState({val: 1 + 1}),立即更新所以后面this.state.val值为2
console.log(this.state.val); // 2
this.setState({val: this.state.val + 1}); // 同理 2 + 1
console.log(this.state.val); // 3
}, 0);
总结
setState是否立即更新与调用栈有关
通过isBatchingUpdates字段来判断组件是否处于一次batchupdates中
需要同步的逻辑最好写在回调函数中
最近答题
基友噢如果喜欢,可以分享给好基友噢如果喜欢,可以分享给好基友噢
关注「JS每日一题」,参与答题!
以上是关于JS每日一题: 如何理解react中setState?的主要内容,如果未能解决你的问题,请参考以下文章
JS每日一题: react的生命周期有哪些?有什么需要注意的地方?