内容简介:转自IMWeb社区,作者:黄qiong,原文链接学过react的人都知道,setState在react里是一个很重要的方法,使用它可以更新我们数据的状态,本篇文章从
转自IMWeb社区,作者:黄qiong,原文链接
前言
学过react的人都知道,setState在react里是一个很重要的方法,使用它可以更新我们数据的状态,本篇文章从 简单使用 到 深入到setState的内部 ,全方位为你揭开setState的神秘面纱~
setState的使用注意事项
setState(updater, callback) 这个方法是用来告诉react组件数据有更新,有可能需要重新渲染。它是异步的,react通常会集齐一批需要更新的组件,然后一次性更新来保证 渲染的性能 ,所以这就给我们埋了一个坑:
那就是在使用 setState 改变状态之后,立刻通过 this.state 去拿最新的状态往往是拿不到的。
要点一
所以第一个使用要点就是:如果你需要基于最新的state做业务的话,可以在 componentDidUpdate 或者 setState 的回调函数里获取。(注:官方推荐第一种做法)
// setState回调函数
changeTitle: function (event) {
this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
// Call API with the updated value
}
复制代码
要点二
设想有一个需求,需要在在onClick里累加两次,如下
onClick = () => {
this.setState({ index: this.state.index + 1 });
this.setState({ index: this.state.index + 1 });
}
复制代码
在react眼中,这个方法最终会变成
Object.assign(
previousState,
{index: state.index+ 1},
{index: state.index+ 1},
...
)
复制代码
由于后面的数据会覆盖前面的更改,所以最终只加了一次.所以如果是下一个state依赖前一个state的话,推荐给setState传function
onClick = () => {
this.setState((prevState, props) => {
return {quantity: prevState.quantity + 1};
});
this.setState((prevState, props) => {
return {quantity: prevState.quantity + 1};
});
}
复制代码
以上是使用setState的两个注意事项,接下来我们来看看setState被调用之后,更新组件的过程,下面是一个简单的流程图。
下面来逐步的解析图里的流程。
一、setState
ReactBaseClassses.js
ReactComponent.prototype.setState = function (partialState, callback) {
// 将setState事务放进队列中
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
复制代码
这里的partialState可以传object,也可以传function,它会产生新的state以一种 Object.assgine() 的方式跟旧的state进行合并。
二、enqueueSetState
enqueueSetState: function (publicInstance, partialState) {
// 获取当前组件的instance
var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');
// 将要更新的state放入一个数组里
var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
queue.push(partialState);
// 将要更新的component instance也放在一个队列里
enqueueUpdate(internalInstance);
}
复制代码
这段代码可以得知,enqueueSetState 做了两件事: 1、将新的state放进数组里 2、用enqueueUpdate来处理将要更新的实例对象
三、enqueueUpdate
ReactUpdates.js
function enqueueUpdate(component) {
// 如果没有处于批量创建/更新组件的阶段,则处理update state事务
if (!batchingStrategy.isBatchingUpdates) {
batchingStrategy.batchedUpdates(enqueueUpdate, component);
return;
}
// 如果正处于批量创建/更新组件的过程,将当前的组件放在dirtyComponents数组中
dirtyComponents.push(component);
}
复制代码
由这段代码可以看到,当前如果正处于创建/更新组件的过程,就不会立刻去更新组件,而是先把当前的组件放在dirtyComponent里,所以不是每一次的setState都会更新组件~。
这段代码就解释了我们常常听说的: setState是一个异步的过程,它会集齐一批需要更新的组件然后一起更新 。
而batchingStrategy 又是个什么东西呢?
四、batchingStrategy
ReactDefaultBatchingStrategy.js
var ReactDefaultBatchingStrategy = {
// 用于标记当前是否出于批量更新
isBatchingUpdates: false,
// 当调用这个方法时,正式开始批量更新
batchedUpdates: function (callback, a, b, c, d, e) {
var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
ReactDefaultBatchingStrategy.isBatchingUpdates = true;
// 如果当前事务正在更新过程在中,则调用callback,既enqueueUpdate
if (alreadyBatchingUpdates) {
return callback(a, b, c, d, e);
} else {
// 否则执行更新事务
return transaction.perform(callback, null, a, b, c, d, e);
}
}
};
复制代码
这里注意两点: 1、如果当前事务正在更新过程中,则使用 enqueueUpdate 将当前组件放在 dirtyComponent 里。 2、如果当前不在更新过程的话,则执行更新事务。
五、transaction
/** * <pre> * wrappers (injected at creation time) * + + * | | * +-----------------|--------|--------------+ * | v | | * | +---------------+ | | * | +--| wrapper1 |---|----+ | * | | +---------------+ v | | * | | +-------------+ | | * | | +----| wrapper2 |--------+ | * | | | +-------------+ | | | * | | | | | | * | v v v v | wrapper * | +---+ +---+ +---------+ +---+ +---+ | invariants * perform(anyMethod) | | | | | | | | | | | | maintained * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|--------> * | | | | | | | | | | | | * | | | | | | | | | | | | * | | | | | | | | | | | | * | +---+ +---+ +---------+ +---+ +---+ | * | initialize close | * +-----------------------------------------+ * </pre> */ 复制代码
简单说明一下transaction对象,它暴露了一个perform的方法,用来执行anyMethod,在anyMethod执行的前,需要先执行所有wrapper的initialize方法,在执行完后,要执行所有wrapper的close方法,就辣么简单。
在ReactDefaultBatchingStrategy.js,tranction 的 wrapper有两个 FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES
var RESET_BATCHED_UPDATES = {
initialize: emptyFunction,
close: function () {
ReactDefaultBatchingStrategy.isBatchingUpdates = false;
}
};
var FLUSH_BATCHED_UPDATES = {
initialize: emptyFunction,
close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
};
var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
复制代码
可以看到,这两个wrapper的 initialize 都没有做什么事情,但是在callback执行完之后,RESET_BATCHED_UPDATES 的作用是将isBatchingUpdates置为false, FLUSH_BATCHED_UPDATES 的作用是执行flushBatchedUpdates,然后里面会循环所有dirtyComponent,调用updateComponent来执行所有的生命周期方法,componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, render, componentDidUpdate 最后实现组件的更新。
以上即为setState的实现过程,最后还是用一个流程图在做一个总结吧~
参考文档:
以上所述就是小编给大家介绍的《揭密React setState》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 揭密 Vue 的双向绑定
- 京东占领首页项目架构揭密
- 亚信安全:揭密APT攻击治理策略
- 揭密全球最大勒索病毒GandCrab的接班人
- 揭密黑产“暴力勒索、毁尸灭迹”运作一条龙
- 揭密首个面向IaaS的查询语言:ZStack Query Language(ZQL)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计数组合学(卷2)
斯坦利 / 机械工业出版社 / 2004-11-15 / 59.00元
本书介绍了生成函数组合、树、代数生成函数、D有限生成函数、非交换生成函数和对称函数。关于对称函数的论述只适用于研究生的入门课程并着重于组合学方面,尤其是Robinson-Schensted-Knuth算法,还讨论了对称函数与表示论之间的联系。附录(由Sergey Fomin编写)中更深入地讨论了对称函数理论,包括jeu de taquin和Littlewood-richardson规则。另外,书中......一起来看看 《计数组合学(卷2)》 这本书的介绍吧!