阅读React源码初尝试(1)

589 阅读3分钟

我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!

1、目的

PS: 这句话必须要写,读了一些源码我发现,他们也只是普通的代码,不过他们考虑到性能/扩展/维护/可读/间接/优秀的逻辑和设计模式,我们应学习这些,当然也不要怕他们是洪水猛兽

  • 之前好像写给如何读源码的,不过那次是简单方法论,这次我们不仅重新总结一下方法,并且实践一下,简单读一读 React

2、方法论

1.问题驱动, 比如 React setState如何起作用的,更新过程是怎样的,React fiber 到底神奇在哪里?如何提升性能的?
2.最新的源码,不仅是思维升级,还是可读性升级,学习成本  🆙 🆙
3.结构,项目有哪些组成部分,为了达到最终的产出,要经过哪几步流程。这些流程里,业界主流的方案有哪几种
4.本地 g clone xxx 拿下来  并且跑起来 ,为了更好的跑起来,找到类似这样的文件 **Contribution Guide** 这个文件会告诉你哪里可以进行预览你的更改
5.在自己想了解的地方 打## debugger && log 然后 想办法 打出自己的 log 
6.关注官网动态和核心开发者动态

image.png

  • 结构更多解释来源于 蚂蚁团队 请放心参考
比如前端 View 层框架,要渲染出 UI,组件要经过 mount、 render 等等步骤。数据驱动的前端框架,
在 mounted 之后,就会进入一个循环,当用户交互触发组件数据变化时,会更新 UI。其中数据的检测方式
又有分 Push 和 Pull 两种方案。渲染 UI 可以是全量的字符串模板替换,也可以是基于 Virtual DOM 的
差量 DOM 更新。

又比如前端的一些工具,Webpack 和 Babel 这些工具都是基于插件的。基本的工作流程就是读取文件,
解析代码成 AST,调用插件去转换 AST,最后生成代码。要了解 Webpack 的原理,就要知道 Webpack 基于
一个叫 [tapable](https://link.zhihu.com/?target=https%3A//github.com/webpack/tapable) 的模块系统
  • 项目结构 更多 解释 需要找到 package / src / bin / lib 下的 核心文件部分
  • 比如 React

image.png Vue

image.png

Babel

image.png

3、实践 以 React setState 为例 看看发生了什么

  • 前提
  • React Core 包含了 React 的类定义和一些顶级 API。大部分的渲染和 View 层 diff 的逻辑都在 Reconciler 和 Renderer 中

步骤总结

1、 找到setState 相关内容

2、setState的入口文件在src/isomorphic/modern/class/ReactBaseClasses.js

  • 此处 挂在 原型链上

Component.prototype.setState = function(partialState, callback) {
  if (
    typeof partialState !== 'object' &&
    typeof partialState !== 'function' &&
    partialState != null
  ) {
    throw new Error(
      'setState(...): takes an object of state variables to update or a ' +
        'function which returns an object of state variables.',
    );
  }
  debugger
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
  • 在看这个入口方法 enqueueSetState 定义 在此处 ReactNoopUpdateQueue.js
function enqueueUpdate(component) {
  ensureInjected();

  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }

  dirtyComponents.push(component);
  if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }
}
if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
dirtyComponents.push(component);

判断batchingStrategy.isBatchingUpdates batchingStrategy是批量更新策略,isBatchingUpdates表示是否处于批量更新过程,开始默认值为false

image.png

3、事务流 batchedUpdates => 调用transaction

var ReactDefaultBatchingStrategy = {
  isBatchingUpdates: false,

  batchedUpdates: function(callback, a, b, c, d, e) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;

    ReactDefaultBatchingStrategy.isBatchingUpdates = true;

    if (alreadyBatchingUpdates) {
      return callback(a, b, c, d, e);
    } else {
      return transaction.perform(callback, null, a, b, c, d, e);
    }
  },
};

module.exports = ReactDefaultBatchingStrategy;

当isBatchingUpdates为true,处于更新事务状态中,则将Component存入dirtyComponent中, 否则调用batchedUpdates处理,发起一个transaction.perform()

4、 batchingStrategy 批量更新策略

var ReactDefaultBatchingStrategy = {
  isBatchingUpdates: false,

  batchedUpdates: function(callback, a, b, c, d, e) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;

    ReactDefaultBatchingStrategy.isBatchingUpdates = true;

    if (alreadyBatchingUpdates) {
      return callback(a, b, c, d, e);
    } else {
      return transaction.perform(callback, null, a, b, c, d, e);
    }
  },
};
  • 非常明显isBatchingUpdates的初始值是false的,在调用batchedUpdates方法的时候会将isBatchingUpdates变量设置为true

4、小结

  • 这是一个 小的切入点,但有了方法和例子,之后的阅读源码将通畅很多,大伙儿 可以赶快试试,有问题可以和我沟通,感谢支持,感谢👍

我的github

Last 参考文档

1.蚂蚁技术团队