引入的模块
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue'); |
其中, ReactNoopUpdateQueue
是默认的 updater ,用来提供 update
, replaceState
, setState
的入队操作,但可能是由于是默认 updater
的原因,只提供了 API 和对入参的校验,但没有提供实际的功能。比如:enqueueSetState: function(
// 需要 render 的实例
publicInstance,
// 接下来要 merge 的 state
partialState,
// 可选参数,setState 组件 update 后的回调
callback,
// 可选参数,调用函数的的名字
callerName,
) {
warnNoop(publicInstance, 'setState');
},
其余几个模块是一些通用辅助模块,就不细说了。
Export 的对象
module.exports = { |
我们依次来看这几个 Component .
ReactComponent
/** |
用来创建基础组件的构造函数,其中 refs
默认是一个空对象,而 updater
默认就是我们上面说的 ReactNoopUpdateQueue
.
setState
ReactComponent.prototype.setState = function(partialState, callback) { |
给它添加 setState
方法,实际操作就是把下一个要设置的 state 放入到更新队列里面。注释中提到:
- 永远使用 setState 这个方法去更改 state ,你应该认为 this.state 是不可变的
- 不保证 this.state 会及时更新,也就是说调用 this.state 可能拿到的还是旧的 state
- 不保证 setState 会同步调用,有可能会把几个 setState 的调用一次性批量更新掉,一定要在某个 setState 的调用完成后执行-操作,可以提供可选的 callback 函数。
- 当一个 callback 函数传入给 setState 的时候,它会在未来的某个时机调用。会用最新的组件参数 (state, props, context). 而这些参数和此时组件本身的 this.* 上的参数值可能会不一样,应为 callback 函数有可能在 receiveProps 之后 shouldComponentUpdate 之前调用,而此时这个新的 state, props 和 context 还没有赋值给 this.
其核心思想就是说, setState 的调用是异步的,从代码 this.updater.enqueueSetState(this, partialState, callback, 'setState');
中可以看到,只是把要更新的 state 放入到了更新队列里面,而不是直接进行 state 的更新。
forceUpdate
ReactComponent.prototype.forceUpdate = function(callback) { |
一个强制更新的方法,这个方法不会触发 shoudleComponentUpdate
,但是会正常调用 componentWillUpdate
和 componentDidUpdate
.
要确保调用这个方法的时候,所有的 DOM 事务操作已经完成。
只有在当你知道一个组件的深层次的 state 变化了,但是并没有调用 setState 的时候才需要调用这个方法。
不推荐的方法
/** |
这里可以看到 isMounted
和 replaceState
这两个方法,已经被官方认为将要废弃的 API ,在开发过程中应该尽量避免使用它们。
PureComponent
function ReactPureComponent(props, context, updater) { |
一个典型 js 实现继承的方式,可以看到 PureComponent 继承自 ReactComponent ,PureComponent 拥有 ReactComponent 的所有属性和方法,并在此基础上多了一个属性:pureComponentPrototype.isPureReactComponent = true;
后面在组件更新部分会用到这个属性。
AsyncComponent
这个组件在我实际开发过程中还没有用到过,我们来看一下:function ReactAsyncComponent(props, context, updater) {
// Duplicated from ReactComponent.
this.props = props;
this.context = context;
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
this.updater = updater || ReactNoopUpdateQueue;
}
var asyncComponentPrototype = (ReactAsyncComponent.prototype = new ComponentDummy());
asyncComponentPrototype.constructor = ReactAsyncComponent;
// Avoid an extra prototype jump for these methods.
Object.assign(asyncComponentPrototype, ReactComponent.prototype);
asyncComponentPrototype.unstable_isAsyncReactComponent = true;
asyncComponentPrototype.render = function() {
return this.props.children;
};
和 PureComponent 一样,同样继承自 ReactComponent. 再次基础上添加了
unstable_isAsyncReactComponent 属性,并设置了 render 方法为直接返回它的 children. 从新添加的属性名可以看到,这是一个还没有稳定下来的特性组件。从名字和内容初步判断是用来创建异步的组件,先用一个 React 组件占位,当 props 传入 children 的时候,在进行渲染,从 render 方法直接 return 可以猜到这样可以实现无多余嵌套 html 标签的组件。
总结
这个模块定义了 React 中会用到的三个基础组件类,需要注意的是:
1. State 应该被看作是 immutable 的,所有的对 state 的修改只能通过 setState 来完成,不能使用 `this.state = **` 来进行 state 的更新
2. setState 是一个异步的操作,所以在调用 setState 后从 this.state 上直接取值可能不是你期望的结果,读取的结果有可能依旧是老的 state
而组件内部的 updater 逻辑,这个模块里面并没有定义具体的执行逻辑。比如调用 setState 后会对要更新的 state 进行入队操作,那么这个操作过程中发生了什么,究竟是如何进行批量的更新的,以及什么时候 state 才会更新完毕,那就需要从其他的模块里来寻找答案了。