react 源码之setState

react

今天看了react源码,仅以记录。

1:monorepo (react 的代码管理方式)

与multirepo 相对。 monorepo是单代码仓库, 是把所有相关项目都集中在一个代码仓库中,每个module独立发布,每个module都有自己的依赖项(package.json),能够作为独立的npm package发布,只是源码放在一起维护。

下图是典型monorepo目录图,react为例

2: setState

✋ setState  "react/src/ReactBaseClasses.js"

 * @param {object|function} partialState Next partial state or function to

* produce next partial state to be merged with current state.

* @param {?function} callback Called after state is updated.

* @final

* @protected

*/

Component.prototype.setState = function(partialState, callback) {

invariant(

typeof partialState === 'object' ||

typeof partialState === 'function' ||

partialState == null,

'setState(...): takes an object of state variables to update or a ' +

'function which returns an object of state variables.',

);

this.updater.enqueueSetState(this, partialState, callback, 'setState');

};

可以看到,干了两件事情:第一:调用方法invariant(), 第二:调用 this.updater.enqueueSetState

✋ invariant() "shared/invariant"  让我们先去看看第一个方法干嘛了!

export default function invariant(condition, format, a, b, c, d, e, f) {

validateFormat(format);

if (!condition) { // 导出了一个方法,可以看出如果condition为false的话, 抛出错误

let error;

if (format === undefined) {

error = new Error(

'Minified exception occurred; use the non-minified dev environment ' +

'for the full error message and additional helpful warnings.',

);

} else {

const args = [a, b, c, d, e, f];

let argIndex = 0;

error = new Error(

format.replace(/%s/g, function() {

return args[argIndex++];

}),

);

error.name = 'Invariant Violation';

}

error.framesToPop = 1; // we don't care about invariant's own frame

throw error;

}

}

得出,这个方法就是判断partialState 的type, 不正确的话抛错误。 Facebook工程师把这个抛错误封装了成了invariant函数,嗯,以后工作中可以这样做!

✋ this.updater.enqueueSetState  让我们再去看看第二个是干嘛了!

首先,this.updater 什么鬼:

import ReactNoopUpdateQueue from './ReactNoopUpdateQueue';

/**

* Base class helpers for the updating state of a component.

*/

function Component(props, context, updater) {//在这个文件中导出了两个构造函数Component和PureComponent

this.props = props;

this.context = context;

// If a component has string refs, we will assign a different object later.

this.refs = emptyObject;

// We initialize the default updater but the real one gets injected by the

// renderer.

this.updater = updater || ReactNoopUpdateQueue; // 这里是this.updater, 这个标黄的 是default updater

}

✋ ReactNoopUpdateQueue  "react/src/ReactNoopUpdateQueue.js" 导出的一个对象,里面有好几个方法,其中一个就是setState用到的this.updater.enqueueSetState(this, partialState, callback, 'setState'):

enqueueSetState: function(

publicInstance, // 实例this

partialState, // 新的state

callback, // 回调

callerName,

) {

warnNoop(publicInstance, 'setState');

},

// 啊 这个里面是default updater

✋  enqueueSetState定义 "react-dom/src/server/ReactPartialRenderer.js"    实际的updater从哪里来的呢?哎,我是暂时没找到,但是,我知道这个实际的updater肯定有enqueueSetState方法,那我就全局搜索一下,找到enqueueSetState的定义:

   let updater = {  //这里是updater对象,里面各种方法

isMounted: function(publicInstance) {

return false;

},

enqueueForceUpdate: function(publicInstance) {

if (queue === null) {

warnNoop(publicInstance, 'forceUpdate');

return null;

}

},

enqueueReplaceState: function(publicInstance, completeState) {

replace = true;

queue = [completeState];

},

enqueueSetState: function(publicInstance, currentPartialState) {

if (queue === null) { // 这是一个错误情况,下面代码中warnNoop()方法就是在dev环境中给出空操作警告的

warnNoop(publicInstance, 'setState');

return null;

}

queue.push(currentPartialState); // 把现在要更新的state push到了一个queue中

},

};

// 接下来代码解决了我上面找不到实际updater的疑问!

let inst;

if (shouldConstruct(Component)) {

inst = new Component(element.props, publicContext, updater); // 在new的时候,就把上面真实的updater传进去啦!!!
.......后面还有好多,不过与我这一期无关了.

✋  queue 这是react提升性能的关键。并不是每次调用setState react都立马去更新了,而是每次调用setState, react只是push到了待更新的queue中! 下面是对这个queue的处理!

      if (queue.length) {

let oldQueue = queue;

let oldReplace = replace;

queue = null;

replace = false;

if (oldReplace && oldQueue.length === 1) { // 队列里面,只有一个,直接更换。

inst.state = oldQueue[0];

} else { // 队列里面有好几个,先进行合并,再更新

let nextState = oldReplace ? oldQueue[0] : inst.state;

let dontMutate = true;

for (let i = oldReplace ? 1 : 0; i < oldQueue.length; i++) {

let partial = oldQueue[i];

let partialState =

typeof partial === 'function'

? partial.call(inst, nextState, element.props, publicContext)

: partial;

if (partialState != null) { // 这里合并啦,新的是nextState

if (dontMutate) {

dontMutate = false;

nextState = Object.assign({}, nextState, partialState);

} else {

Object.assign(nextState, partialState);

}

}

}

inst.state = nextState; //最后赋值给实例

}

} else {

queue = null;

}

以上是 react 源码之setState 的全部内容, 来源链接: utcz.com/z/383662.html

回到顶部