react 源码之setState

更新日期: 2019-02-26阅读: 2.4k标签: 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函数,嗯,以后工作中可以这样做!

his.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;
      }


 原文来自:https://www.cnblogs.com/yadiblogs/archive/2019/02/27/10446748.html


链接: https://fly63.com/article/detial/2143

如何优雅的设计 React 组件

如今的 Web 前端已被 React、Vue 和 Angular 三分天下,尽管现在的 jQuery 已不再那么流行,但 jQuery 的设计思想还是非常值得致敬和学习的,特别是 jQuery 的插件化。

React深度编程:受控组件与非受控组件

受控组件与非受控组件在官网与国内网上的资料都不多,有些人觉得它可有可不有,也不在意。这恰恰显示React的威力,满足不同规模大小的工程需求。

React框架学习_关于React两种构建应用方式选择

一般在传统模式下,我们构建前端项目很简单。就是下载各种js文件,如JQuery、Echart等,直接放置在html静态文件。Webpack则是JavaScript中比较知名的打包工具。这两个构建工具构成了React应用快速搭建的基础。

Gatsby.js_一款基于React.js静态站点生成工具

Gatsby能快速的使用 React 生态系统来生成静态网站,可以结合React Component、Markdown 和服务端渲染来完成静态网站生成让他更强大。

React创建组件的三种方式及其区别

React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归;具体的三种方式:函数式定义的无状态组件、es5原生方式React.createClass定义的组件、es6形式的extends React.Component定义的组件

react生命周期详解_深入理解React生命周期

React主要思想是通过构建可复用组件来构建用户界面,每个组件都有自己的生命周期,它规定了组件的状态和方法需要在哪个阶段改变和执行。所谓组件就是有限状态机,,表示有限个状态以及在这些状态之间的转移和动作行为的模型。

React + Webpack 构建打包优化

React 相关的优化:使用 babel-react-optimize 对 React 代码进行优化,检查没有使用的库,去除 import 引用,按需打包所用的类库,比如 lodash 、echarts 等.Webpack 构建打包存在的问题两个方面:构建速度慢,打包后的文件体积过大

react router中页面传值的三种方法

这篇文章主要介绍React Router定义路由之后如何传值,有关React和React Router 。react router中页面传值的三种方法:props.params、query、state

react 高阶组件的 理解和应用

react 高阶组件简单的理解是:一个包装了另一个基础组件的组件。高阶组件的两种形式:属性代理(Props Proxy)、反向继承 (Inheritance Inversion)

react中的refs属性的使用方法

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!