React setState 全解析:深入源码挖掘执行机制,揭秘同步异步表现及对象参数设置问题
2024-01-24 09:10:33
深入源码理解 setState 执行机制
_pendingState: null,
_pendingCallbacks: null,
setState 方法其实是一个非阻塞操作,不会阻塞页面的渲染。React 会先将更新信息存储在_pendingState和_pendingCallbacks中,然后在下一帧才会触发真正的组件重新渲染。
if (updateBatching === null) {
updateBatching = 0;
// Transition to start a batch.
renderPhaseUpdates = [];
ReactCurrentBatchConfig = batchConfig;
}
当触发setState时,React 会检查一个全局变量updateBatching是否为null。如果为null,则创建一个新的批处理,并将setState的信息存储在renderPhaseUpdates中。
// Previous state, if we're not currently
// batching an update
if (updateBatching > 0) {
shouldComponentUpdate = false;
prevState = updater.isReplace
? emptyObject
: combinedState;
newSimpleState = booleanKey ? newSimpleState[0] : newSimpleState;
isStateObj = typeof newSimpleState === 'object';
}
如果当前正在批处理更新,则shouldComponentUpdate设置为false,prevState设置为当前的状态,newSimpleState设置为新的状态。
if (
typeof updater === 'function'
) {
updater = updater.call(
currentState,
prevState,
props
);
如果updater是一个函数,则调用该函数,并以当前状态、prevState和props作为参数。
nextUpdater = null;
if (nextUpdater) {
// Determine what the next state should be, and recompute
// the nextPropSet if propDeps changed. We might cycle through
// several sets of updates while processing.
var nextState = nextUpdater.call(
currentState,
combinedState,
nextPropSet
);
如果nextUpdater不为空,则调用nextUpdater,并以当前状态、combinedState和nextPropSet作为参数。
currentState = combinedState;
prevProps = currentProps;
currentProps = nextPropSet;
if (currentContext === null) {
currentContext = emptyContextObject;
}
将currentState设置为combinedState,prevProps设置为currentProps,currentProps设置为nextPropSet,currentContext设置为emptyContextObject。
updateBatching = null;
ReactCurrentBatchConfig = null;
renderPhaseUpdates.forEach(beginPhase);
将updateBatching和ReactCurrentBatchConfig设置为null,并调用beginPhase函数,对renderPhaseUpdates中的每个更新进行处理。
同步/异步执行的背后原因
setState 的同步/异步执行取决于当前是否处于事件处理过程中。如果在事件处理过程中调用 setState,则该更新是异步的;否则,该更新是同步的。
这是因为 React 在事件处理过程中不会立即更新状态,而是将更新信息存储在_pendingState和_pendingCallbacks中,然后在下一帧才会触发真正的组件重新渲染。这样做是为了避免在事件处理过程中对 DOM 进行不必要的更新,从而提高性能。
对象参数设置仅生效最后一次的原因
当使用对象作为 setState 的参数时,只有最后一次设置的对象参数才会生效。这是因为 React 在更新状态时,会将新的状态与之前的状态进行合并,如果新的状态也是一个对象,则会覆盖之前的状态,从而导致只有最后一次设置的对象参数生效。
为了解决这个问题,可以将对象参数中的属性逐个传入 setState,这样就可以确保每个属性都能正确更新。
this.setState({
name: 'Alice',
age: 20,
});
结语
setState 是 React 中一项非常重要的工具,它允许组件更新自己的状态,从而触发重新渲染。通过深入了解 setState 的执行机制,我们能够更好地理解 React 的工作原理,并避免在使用 setState 时遇到问题。