首页 > 语言 > JavaScript > 正文

深入研究React中setState源码

2024-05-06 15:24:22
字体:
来源:转载
供稿:网友

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;  }  //这里,初始化queue变量,同时初始化 internalInstance._pendingStateQueue = [ ] ;  //对于 || 的短路运算还是要多梳理下  //queue数组(模拟队列)中存放着setState放进来的对象;  var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);  //这里将partialState放入queue数组中,也就是internalInstance._pendingStateQueue 数组中,此时,每次setState的partialState,都放进了React组件实例对象上的_pendingStateQueue属性中,成为一个数组;  queue.push(partialState);  enqueueUpdate(internalInstance); },};module.exports = ReactUpdateQueue;            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选