今天看了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函数,嗯,以后工作中可以这样做!

✋ this.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;
}

react 源码之setState的更多相关文章

  1. React源码剖析系列 - 生命周期的管理艺术

    目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理.本系列文章希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期(C ...

  2. React 源码剖析系列 - 生命周期的管理艺术

    目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理. 本系列文章 希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期 ...

  3. React源码 commit阶段详解

    转: React源码 commit阶段详解 点击进入React源码调试仓库. 当render阶段完成后,意味着在内存中构建的workInProgress树所有更新工作已经完成,这包括树中fiber节点 ...

  4. React源码解析:ReactElement

    ReactElement算是React源码中比较简单的部分了,直接看源码: var ReactElement = function(type, key, ref, self, source, owne ...

  5. React 源码剖析系列 - 不可思议的 react diff

      简单点的重复利用已有的dom和其他REACT性能快的原理. key的作用和虚拟节点 目前,前端领域中 React 势头正盛,使用者众多却少有能够深入剖析内部实现机制和原理. 本系列文章希望通过剖析 ...

  6. 读react源码准备

    git源码地址:https://github.com/facebook/react react 里面就是 react源码 react里面的react文件夹就是react源码,react源码非常的少,总 ...

  7. react源码之render

    1.最近学习react源码,刚刚入门,看了render的原理,到了fiberRoot的创建 如图:

  8. React躬行记(16)——React源码分析

    React可大致分为三部分:Core.Reconciler和Renderer,在阅读源码之前,首先需要搭建测试环境,为了方便起见,本文直接采用了网友搭建好的环境,React版本是16.8.6,与最新版 ...

  9. React源码之组件的实现与首次渲染

    react: v15.0.0 本文讲 组件如何编译 以及 ReactDOM.render 的渲染过程. babel 的编译 babel 将 React JSX 编译成 JavaScript. 在 ba ...

随机推荐

  1. idea注册码

     2019 idea  注册码:   N757JE0KCT-eyJsaWNlbnNlSWQiOiJONzU3SkUwS0NUIiwibGljZW5zZWVOYW1lIjoid3UgYW5qdW4iLC ...

  2. CPU运行原理

    问题: CPU位宽表示什么意思? 下面这个是 https://www.bilibili.com/video/av9667986?from=search&seid=336127932106862 ...

  3. Python基础之面向对象思维解决游戏《天龙八部》

    一.程序设计思维: 以面向对象的思维设计<天龙八部>游戏技能,使得技能效果在增加或者减少时,游戏技能整体框架不改变,仅仅增加或者减少技能效果 二.思路流程图如下: 三.变成框架实现代码: ...

  4. C#嵌套类

    { "children" : [{ "children" : [{ "children" : [], "name" : ...

  5. C++之几个最常

    1.同类对象间的数据共享——静态成员 静态数据成员声明静态数据成员要采用关键字static:类静态数据成员的定义和初始化定义:static 数据类型 成员名:初始化:数据类型 类名::静态数据成员名= ...

  6. DCOS实践分享(6):基于DCOS的大数据应用分享

    Open DC/OS大中华区官方发布会在京隆重召开   DCOS领域诞生了一个100%开源的企业级Datacenter Operating System版本,即DC/OS.Linker Network ...

  7. .NET Core跨平台的奥秘[中篇]:复用之殇

    在<.NET Core跨平台的奥秘[上篇]:历史的枷锁>中我们谈到:由于.NET是建立在CLI这一标准的规范之上,所以它天生就具有了"跨平台"的基因.在微软发布了第一个 ...

  8. kali linux学习笔记(四) : 网络端口大全介绍

    端口大全介绍 2端口:管理实用程序 3端口:压缩进程 5端口:远程作业登录 7端口:回显 9端口:丢弃 11端口:在线用户 13端口:时间 17端口:每日引用 18端口:消息发送协议 19端口:字符发 ...

  9. Python公众号开发(二)—颜值检测

    上篇文章,我们把自己的程序接入了微信公众号,并且能把用户发送的文本及图片文件原样返回.今天我们把用户的图片通过腾讯的AI平台分析后再返回给用户. 为了防止我的文章被到处转载,贴一下我的公众号[智能制造 ...

  10. NIO类库

    NIO概述 从JDK1.4开始,引入了新的I/O类库,它们位于java.nio包中,其目的在于提高I/O的操作效率.nio是new io的缩写. 参考文章:NIO BIO AIO区别 java.nio ...