深入研究深入研究React中中setState源码源码
主要介绍了深入研究React中setState源码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
React作为一门前端框架,虽然只是focus在MVVM中的View部分,但还是实现了View和model的绑定。修改数据的同时,可以实现View的刷新。这大大简化了我们的逻辑,只用关心数据流的变化,同时
减少了代码量,使得后期维护也更加方便。这个特性则要归功于setState()方法。React中利用队列机制来管理state,避免了很多重复的View刷新。下面我们来从源码角度探寻下setState机制。
1 还是先声明一个组件,从最开始一步步来寻源;
class App extends Component {
//只在组件重新加载的时候执行一次
constructor(props) {
super(props);
//..
}
//other methods
}
//ReactBaseClasses.js中如下:这里就是setState函数的来源;
//super其实就是下面这个函数
function ReactComponent(props, context, updater) {
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;
}
ReactComponent.prototype.setState = function (partialState, callback) {
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
所以主要来看是否传入了updater参数,也就是说何时进行 new 组件;具体的updater参数是怎么传递进来的,以及是那个对象,参见
react源码分析系列文章下面的react中context updater到底是如何传递的
这里直接说结果,updater对象其实就是ReactUpdateQueue.js 中暴漏出的ReactUpdateQueue对象;
2 既然找到了setState之后执行的动作,我们在一步步深入进去
class Root extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
let me = this;
me.setState({
count: me.state.count + 1
});
console.log(me.state.count); // 打印出0
me.setState({
count: me.state.count + 1
});
console.log(me.state.count); // 打印出0
setTimeout(function(){
me.setState({
count: me.state.count + 1
});
console.log(me.state.count); // 打印出2
}, 0);
setTimeout(function(){
me.setState({
count: me.state.count + 1
});
console.log(me.state.count); // 打印出3
}, 0);
}
render() {
return (
<h1>{this.state.count}</h1>
)
}
}
ReactComponent.prototype.setState = function (partialState, callback) {
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
ReactUpdateQueue.js
var ReactUpdates = require('./ReactUpdates');
function enqueueUpdate(internalInstance) {
ReactUpdates.enqueueUpdate(internalInstance);
};
function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
//在ReactCompositeComponent.js中有这样一行代码,这就是其来源;
// Store a reference from the instance back to the internal representation
//ReactInstanceMap.set(inst, this);
var internalInstance = ReactInstanceMap.get(publicInstance);
//返回的是在ReactCompositeComponent.js中construct函数返回的对象;ReactInstance实例对象并不是简单的new 我们写的组件的实例对象,而是经过instantiateReactComponent.js中ReactCompositeComponentWrapper函数包装的对象;详见 创建React组件方式以及源码分析.md
return internalInstance;
};
var ReactUpdateQueue = {
//。。。。省略其他代码
enqueueCallback: function (publicInstance, callback, callerName) {
ReactUpdateQueue.validateCallback(callback, callerName);
var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);
if (!internalInstance) {
return null;
}
//这里将callback放入组件实例的_pendingCallbacks数组中;
if (internalInstance._pendingCallbacks) {
internalInstance._pendingCallbacks.push(callback);
} else {
internalInstance._pendingCallbacks = [callback];
}
// TODO: The callback here is ignored when setState is called from
// componentWillMount. Either fix it or disallow doing so completely in
// favor of getInitialState. Alternatively, we can disallow
// componentWillMount during server-side rendering.
enqueueUpdate(internalInstance);
},
enqueueSetState: function (publicInstance, partialState) {
var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');
if (!internalInstance) {
return;