Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >React源码解读【一】API复习与基础

React源码解读【一】API复习与基础

作者头像
合一大师
发布于 2020-07-20 02:13:56
发布于 2020-07-20 02:13:56
70000
代码可运行
举报
文章被收录于专栏:JavaScript全栈JavaScript全栈
运行总次数:0
代码可运行

人生就是你所有选择的总和。那么,你今天要做什么?——阿尔贝·加缪

四年,如人生小溪中的一洼清水,如历史长河中的一点水滴,而却就是这四年,我完成了从懵懂到成熟的蜕变。回首这四年,有过创业,有过生病,有过说不出的苦楚,也有过让我笑不间断的喜悦。

那年的背包,依然在背着;那年的代码,依然还在用类似的逻辑实现着;一件好的东西总会让我爱不释手,react就是其中一个,从React.createClass到React.createElement到React.Component;从Mixin到class component到functional component;从flux到redux、mobx到hooks;每一次更进一步,每一次爱更深一筹。就在这个时间节点,我觉得我作为一个禅意开发者,应该纪念一下我这位老情人了。

这一系列文章与视频讲解(微信公众号:《JavaScript全栈》)将深入剖析React源码。

如需倍速播放视频,bilibili搜索:合一大师

为了保证源码一致,请阅读与本文及视频相同版本,可到github下载,地址:https://github.com/Walker-Leee/react-learn-code-v16.12.0

解读安排如下

好了,感慨发完,我们来一起揭开React神秘面纱吧!

React基础与API

早期做react开发的同学应该都知道,最开始react和react-dom在同一个包,后来为了做平台移植性,将react与react-dom分拆,相信做过react-native的同学都知道,我们写react-native项目时,也是用的react,只是表现层用了react-native的组件与api。所以看react源码我们先分析react对于api的定义。

我将react中的部分代码片段展示于此

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import {Component, PureComponent} from './ReactBaseClasses';
import {createRef} from './ReactCreateRef';
import {forEach, map, count, toArray, only} from './ReactChildren';
import {
  createElement,
  createFactory,
  cloneElement,
  isValidElement,
  jsx,
} from './ReactElement';
import {createContext} from './ReactContext';
import {lazy} from './ReactLazy';
import forwardRef from './forwardRef';
import memo from './memo';
import {
  useCallback,
  useContext,
  useEffect,
  useImperativeHandle,
  useDebugValue,
  useLayoutEffect,
  useMemo,
  useReducer,
  useRef,
  useState,
  useResponder,
  useTransition,
  useDeferredValue,
} from './ReactHooks';

Component 与 PureComponent

两者的区别在于,PureComponent多给了一个标识,通过该标识在ReactFiberClassComponent中处理,决定是否进行shalloEqual。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
  return (
    !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
  );
}

比较state和props的值,来判断是否需要更新。

类似该对比的地方还有一个,就是在 shouldComponentUpdate

createRef

更新后的ref用法,我们可以看到React即将抛弃<div>123</div> ,以后只能使用以下两种方式使用ref。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class App extends React.Component{

  constructor() {
    this.ref = React.createRef()
  }

  render() {
    return <div ref={this.ref} />
    // 或者是
    return <div ref={(node) => this.ref = node} />
  }

}

forwardRef

用来解决组件封装时,ref 的传递问题,大家看过antd源码的应该知道,很多组件使用到了 forwardRef 。比如form组件中,@Form.create() 将form组件相关的props绑定到组件上,this.props.validate

ReactChildren

该文件中包含api有:forEach, map, count, toArray, only ,这些方法都是对于reactChildren的处理。

createElement 与 cloneElement

我们在使用react似乎少见createElement方法,因为在我们现在项目中大多用上了jsx,大多时候是babel帮我们将jsx转换为createElement,React.createElement('h1', {id: 'title'}, 'hello world')

cloneElement顾名思义,拷贝已有元素。

memo

函数组件中类似pureComponent的用法,浅比较函数式组件的props,确定是否需要更新。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default function memo<Props>(
  type: React$ElementType,
  compare?: (oldProps: Props, newProps: Props) => boolean,
) {
  return {
    $$typeof: REACT_MEMO_TYPE,
    type,
    compare: compare === undefined ? null : compare,
  };
}

ReactElement

在react中,调用createElement方法,返回值为ReactElement

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export function createElement(type, config, children) {
  // ...
  
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props,
  );
}

// 与createElement相比较,预先定义ReactElement的type值,并返回ReactElement
export function createFactory(type) {
  const factory = createElement.bind(null, type);
  factory.type = type;
  return factory;
}

我们再来看看ReactElement的定义

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // This tag allows us to uniquely identify this as a React Element
    // 该参数指明React节点类型
    $$typeof: REACT_ELEMENT_TYPE,

    // Built-in properties that belong on the element
    // 标识该ReactElement属于什么类型
    type: type,
    key: key,
    ref: ref,
    props: props,

    // Record the component responsible for creating this element.
    // 记录
    _owner: owner,
  };

  return element;
};

我们可以发现,ReactElement 只是一个用来记录节点相关信息的对象,在后续的操作中通过该对象中的这些属性值,执行不同类型逻辑。同时,这些信息在不同平台渲染时,提供了脱离平台的能力。

Fiber、FiberRoot

FiberRoot

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type BaseFiberRootProperties = {|
  // 挂载节点,在ReactDOM.render方法接收的第二个参数
  containerInfo: any,
  // 在持久更新时用到该属性,换言之不支持增量更新平台,在react-dom中不涉及
  pendingChildren: any,
  // 当前应用对应的Fiber,即Root Fiber
  current: Fiber,

  // 以下顺序表示优先级
  // 1) 还没提交(committed)的任务
  // 2) 还未提交的挂起任务
  // 3) 未提交的可能被挂起的任务
  // 在提交时被挂起最老和最新任务
  earliestSuspendedTime: ExpirationTime,
  latestSuspendedTime: ExpirationTime,
  // The earliest and latest priority levels that are not known to be suspended.
  // 不确定是否会挂起的最老和最新任务(所有任务初始化都是该状态)
  earliestPendingTime: ExpirationTime,
  latestPendingTime: ExpirationTime,
  // The latest priority level that was pinged by a resolved promise and can be retried.
  latestPingedTime: ExpirationTime,

  // 如果有抛出错误且此时没有更多更新,此时我们将尝试在处理错误前同步从头渲染
  // 在renderRoot出现无法处理的错误时,该值会被置为`true`
  didError: boolean,

  // 等待提交任务的`expirationTime`属性
  pendingCommitExpirationTime: ExpirationTime,
  // 已经完成的任务的FiberRoot对象,如果你只有一个Root,那他永远只可能是这个Root对应的Fiber,或者是null
  // 在commit阶段,只会处理这个值对应的任务
  finishedWork: Fiber | null,
  // 在任务被挂起时,通过setTimeout设置的返回内容,用来下一次如果有新的任务挂起时清理还没触发的timeout
  timeoutHandle: TimeoutHandle | NoTimeout,
  // 顶层context对象,只有主动调用renderSubtreeIntoContainer时才会使用到
  context: Object | null,
  pendingContext: Object | null,
  // 用来确定在第一次渲染时,是否需要合并
  hydrate: boolean,
  // 当前root对象上所剩余的过期时间
  nextExpirationTimeToWorkOn: ExpirationTime,
  // 当前更新对应的过期时间
  expirationTime: ExpirationTime,
  // List of top-level batches. This list indicates whether a commit should be
  // deferred. Also contains completion callbacks.
  // 顶层批处理任务,该变量指明一个commit是否应该被推迟处理,同时包含了完成处理后的回调
  firstBatch: Batch | null,
  // root之间关联的链表结构
  nextScheduledRoot: FiberRoot | null,
|};

Fiber

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Fiber对应一个需要被处理或者已经处理的组件,组件与Fiber可以是一对多关系
type Fiber = {|
  // 不同的组件类型
  tag: WorkTag,

  // ReactElement里面的key
  key: null | string,

  // ReactElement.type,我们调用`createElement`的第一个参数
  elementType: any,

  // The resolved function/class/ associated with this fiber.
  // 异步组件resolved之后返回的内容,一般是`function`或者`class`,表示函数或class
  type: any,

  // The local state associated with this fiber.
  // 跟当前Fiber相关本地状态(若在浏览器环境中,该值为DOM节点)
  stateNode: any,

  // 指向他在Fiber节点树中的`parent`,用来在处理完这个节点之后向上返回
  return: Fiber | null,

  // 指向自身的第一个子节点
  // 单链表树结构
  child: Fiber | null,
  // 指向自身的兄弟节点
  // 兄弟节点的return与之指向同一个父节点
  sibling: Fiber | null,
  index: number,

  // ref属性
  ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject,

  // 新的更新带来的props
  pendingProps: any,
  // 上次渲染完成后的props
  memoizedProps: any,

  // 队列,存放该Fiber对应的组件产生的Update
  updateQueue: UpdateQueue<any> | null,

  // 上一次渲染时的state
  memoizedState: any,

  // 列表,存放这个Fiber依赖的context
  firstContextDependency: ContextDependency<mixed> | null,

  // 用来描述当前Fiber和他子树的`Bitfield`
  // 共存的模式表示这个子树是否默认是异步渲染的
  // Fiber被创建的时候他会继承父Fiber
  // 其他的标识也可以在创建的时候被设置
  // 但是在创建之后不应该再被修改,特别是他的子Fiber创建之前
  mode: TypeOfMode,

  // Effect
  // 用来记录Side Effect
  effectTag: SideEffectTag,

  // 单链表用来快速查找下一个side effect
  nextEffect: Fiber | null,

  // 子树中第一个side effect
  firstEffect: Fiber | null,
  // 子树中最后一个side effect
  lastEffect: Fiber | null,

  // 代表任务在未来的哪个时间点应该被完成
  // 不包括他的子树产生的任务
  expirationTime: ExpirationTime,

  // 快速确定子树中是否有不在等待的变化
  childExpirationTime: ExpirationTime,

  // 在Fiber树更新的过程中,每个Fiber都会有一个跟其对应的Fiber,current <==> workInProgress
  //在渲染完成后,保存fiber
  alternate: Fiber | null,

  // 调试相关,收集每个Fiber和子树渲染时间

  actualDuration?: number,
  actualStartTime?: number,
  selfBaseDuration?: number,
  treeBaseDuration?: number,
  _debugID?: number,
  _debugSource?: Source | null,
  _debugOwner?: Fiber | null,
  _debugIsCurrentlyTiming?: boolean,
|};

effectTags、ReactWorkTag、sideEffects

这三个文件主要定义了react中操作相关的类型,值得一提的是,react中类型的定义与组合很巧妙,如果同学之前未使用过这种思路,可以在权限设计系统中试用该方法。

effectTags

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

export type SideEffectTag = number;

// Don't change these two values. They're used by React Dev Tools.
export const NoEffect = /*              */ 0b00000000000;
export const PerformedWork = /*         */ 0b00000000001;

// You can change the rest (and add more).
export const Placement = /*             */ 0b00000000010;
export const Update = /*                */ 0b00000000100;
export const PlacementAndUpdate = /*    */ 0b00000000110;
export const Deletion = /*              */ 0b00000001000;
export const ContentReset = /*          */ 0b00000010000;
export const Callback = /*              */ 0b00000100000;
export const DidCapture = /*            */ 0b00001000000;
export const Ref = /*                   */ 0b00010000000;
export const Snapshot = /*              */ 0b00100000000;

// Update & Callback & Ref & Snapshot
export const LifecycleEffectMask = /*   */ 0b00110100100;

// Union of all host effects
export const HostEffectMask = /*        */ 0b00111111111;

export const Incomplete = /*            */ 0b01000000000;
export const ShouldCapture = /*         */ 0b10000000000;

ReactWorkTag

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export const FunctionComponent = 0;
export const ClassComponent = 1;
export const IndeterminateComponent = 2; // Before we know whether it is function or class
export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
export const HostComponent = 5;
export const HostText = 6;
export const Fragment = 7;
export const Mode = 8;
export const ContextConsumer = 9;
export const ContextProvider = 10;
export const ForwardRef = 11;
export const Profiler = 12;
export const SuspenseComponent = 13;
export const MemoComponent = 14;
export const SimpleMemoComponent = 15;
export const LazyComponent = 16;
export const IncompleteClassComponent = 17;

sideEffects

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

export type SideEffectTag = number;

// Don't change these two values. They're used by React Dev Tools.
export const NoEffect = /*              */ 0b00000000000;
export const PerformedWork = /*         */ 0b00000000001;

// You can change the rest (and add more).
export const Placement = /*             */ 0b00000000010;
export const Update = /*                */ 0b00000000100;
export const PlacementAndUpdate = /*    */ 0b00000000110;
export const Deletion = /*              */ 0b00000001000;
export const ContentReset = /*          */ 0b00000010000;
export const Callback = /*              */ 0b00000100000;
export const DidCapture = /*            */ 0b00001000000;
export const Ref = /*                   */ 0b00010000000;
export const Snapshot = /*              */ 0b00100000000;

// Update & Callback & Ref & Snapshot
export const LifecycleEffectMask = /*   */ 0b00110100100;

// Union of all host effects
export const HostEffectMask = /*        */ 0b00111111111;

export const Incomplete = /*            */ 0b01000000000;
export const ShouldCapture = /*         */ 0b10000000000;

Update、UpdateQueue

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export type Update<State> = {
  // 更新的过期时间
  expirationTime: ExpirationTime,

  // 该tag标识更新类型
  // UpdateState -> 0;
  // ReplaceState -> 1;
  // ForceUpdate -> 2;
  // CaptureUpdate -> 3;
  tag: 0 | 1 | 2 | 3,
  // 更新内容,如调用setState时接收的第一个参数
  payload: any,
  // 对应的回调函数,调用setState或render时
  callback: (() => mixed) | null,

  // 指向下一个更新
  next: Update<State> | null,
  // 指向下一个side effect
  nextEffect: Update<State> | null,
};

export type UpdateQueue<State> = {
  // 每次操作完更新后的state
  baseState: State,

  // 队首的Update
  firstUpdate: Update<State> | null,
  // 队尾的Update
  lastUpdate: Update<State> | null,

  firstCapturedUpdate: Update<State> | null,
  lastCapturedUpdate: Update<State> | null,

  firstEffect: Update<State> | null,
  lastEffect: Update<State> | null,

  firstCapturedEffect: Update<State> | null,
  lastCapturedEffect: Update<State> | null,
};

React.Children

数据结构中有一个结构——链表,不知可否记得链表的遍历?最常见链表的遍历使用递归实现,该api实现就是借助递归。我们以forEach为例来看看代码片段实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function forEachChildren(children, forEachFunc, forEachContext) {
  if (children == null) {
    return children;
  }
  const traverseContext = getPooledTraverseContext(
    null,
    null,
    forEachFunc,
    forEachContext,
  );
  traverseAllChildren(children, forEachSingleChild, traverseContext);
  releaseTraverseContext(traverseContext);
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function traverseAllChildrenImpl(
  children,
  nameSoFar,
  callback,
  traverseContext,
) {
  const type = typeof children;

  if (type === 'undefined' || type === 'boolean') {
    // All of the above are perceived as null.
    children = null;
  }

  let invokeCallback = false;

  if (children === null) {
    invokeCallback = true;
  } else {
    switch (type) {
      case 'string':
      case 'number':
        invokeCallback = true;
        break;
      case 'object':
        switch (children.$$typeof) {
          case REACT_ELEMENT_TYPE:
          case REACT_PORTAL_TYPE:
            invokeCallback = true;
        }
    }
  }

  if (invokeCallback) {
    callback(
      traverseContext,
      children,
      // If it's the only child, treat the name as if it was wrapped in an array
      // so that it's consistent if the number of children grows.
      nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,
    );
    return 1;
  }

  let child;
  let nextName;
  let subtreeCount = 0; // Count of children found in the current subtree.
  const nextNamePrefix =
    nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;

  if (Array.isArray(children)) {
    for (let i = 0; i < children.length; i++) {
      child = children[i];
      nextName = nextNamePrefix + getComponentKey(child, i);
      subtreeCount += traverseAllChildrenImpl(
        child,
        nextName,
        callback,
        traverseContext,
      );
    }
  } else {
    const iteratorFn = getIteratorFn(children);
    if (typeof iteratorFn === 'function') {

      const iterator = iteratorFn.call(children);
      let step;
      let ii = 0;
      while (!(step = iterator.next()).done) {
        child = step.value;
        nextName = nextNamePrefix + getComponentKey(child, ii++);
        subtreeCount += traverseAllChildrenImpl(
          child,
          nextName,
          callback,
          traverseContext,
        );
      }
    } else if (type === 'object') {
      let addendum = '';
      const childrenString = '' + children;
      invariant(
        false,
        'Objects are not valid as a React child (found: %s).%s',
        childrenString === '[object Object]'
          ? 'object with keys {' + Object.keys(children).join(', ') + '}'
          : childrenString,
        addendum,
      );
    }
  }

  return subtreeCount;
}

function traverseAllChildren(children, callback, traverseContext) {
  if (children == null) {
    return 0;
  }

  return traverseAllChildrenImpl(children, '', callback, traverseContext);
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const POOL_SIZE = 10;
const traverseContextPool = [];
function releaseTraverseContext(traverseContext) {
  traverseContext.result = null;
  traverseContext.keyPrefix = null;
  traverseContext.func = null;
  traverseContext.context = null;
  traverseContext.count = 0;
  if (traverseContextPool.length < POOL_SIZE) {
    traverseContextPool.push(traverseContext);
  }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JavaScript全栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
React.forwardRef的应用场景及源码解析
ref 的作用是获取实例,可能是 DOM 实例,也可能是 ClassComponent 的实例。
进击的小进进
2020/02/24
2.2K0
React.forwardRef的应用场景及源码解析
React源码解析之RootFiber
一、Fiber的含义和作用 (1)每一个ReactElement对应一个Fiber对象
进击的小进进
2019/09/05
6050
React源码解析之RootFiber
【React源码解读】- 组件的实现
react使用也有一段时间了,大家对这个框架褒奖有加,但是它究竟好在哪里呢? 让我们结合它的源码,探究一二!(当前源码为react16,读者要对react有一定的了解)
用户2356368
2024/02/04
1220
【React源码解读】- 组件的实现
【React源码解读】- 组件的实现
react使用也有一段时间了,大家对这个框架褒奖有加,但是它究竟好在哪里呢? 让我们结合它的源码,探究一二!(当前源码为react16,读者要对react有一定的了解)
用户2356368
2019/04/03
7060
【React源码解读】- 组件的实现
React 源码:ReactElement 和 FiberNode 是什么?
大家好,我是前端西瓜哥。今天学习一下 ReactElement 和 FiberNode。
前端西瓜哥
2022/12/21
9440
React 源码:ReactElement 和 FiberNode 是什么?
React 16.3新API
之前也有context,相当于自动向下传递的props,子树中的任意组件都可以从context中按需取值(配合contextTypes声明)
ayqy贾杰
2019/06/12
1.1K0
React 16.3新API
React源码解析之React.children.map()
React.Children.map(props.children, item => [item, [item, [item]]] :
进击的小进进
2019/09/05
1.1K0
React源码解析之React.children.map()
ReactDOM.render在react源码中执行之后发生了什么?
通常是如下图使用,在提供的 container 里渲染一个 React 元素,并返回对该组件的引用(或者针对无状态组件返回 null)。本文主要是将ReactDOM.render的执行流程在后续文章中会对创建更新的细节进行分析,文中的源代码部分为了方便阅读将__DEV__部分的代码移除掉了。
flyzz177
2022/09/30
5750
react源码解析5.jsx&核心api
一句话概括就是,用js对象表示dom信息和结构,更新时重新渲染更新后的对象对应的dom,这个对象就是React.createElement()的返回结果
用户9002110
2021/12/04
4120
react源码解析5.jsx&核心api
一句话概括就是,用js对象表示dom信息和结构,更新时重新渲染更新后的对象对应的dom,这个对象就是React.createElement()的返回结果
zz1998
2021/11/30
4220
react源码解析5.jsx&核心api
一句话概括就是,用js对象表示dom信息和结构,更新时重新渲染更新后的对象对应的dom,这个对象就是React.createElement()的返回结果
全栈潇晨
2021/06/04
4850
react源码解析5.jsx&核心api
React源码学习进阶(五)beginWork如何处理Fiber
beginWork的代码位于packages/react-reconciler/src/ReactFiberBeginWork.js:
孟健
2022/12/19
4030
React源码学习进阶(五)beginWork如何处理Fiber
react源码解析--jsx&核心api
一句话概括就是,用js对象表示dom信息和结构,更新时重新渲染更新后的对象对应的dom,这个对象就是React.createElement()的返回结果
长腿程序员165858
2022/12/12
3680
React源码解析之FunctionComponent(上)
在 React源码解析之workLoop 中讲到当workInProgress.tag为FunctionComponent时,会进行FunctionComponent的更新:
进击的小进进
2019/12/02
1K0
React 进阶 - JSX
最后,在调和阶段,上述 React element 对象的每一个子节点都会形成一个对应的 fiber 对象,然后通过 sibling、return、child 将每一个 fiber 对象联系起来。
Cellinlab
2023/05/17
7980
React 进阶 - JSX
2.react心智模型(来来来,让大脑有react思维吧)
​ 视频课程的目的是为了快速掌握react源码运行的过程和react中的scheduler、reconciler、renderer、fiber等,并且详细debug源码和分析,过程更清晰。
zz1998
2021/12/09
7600
小前端读源码 - React16.7.0(四)
继续上一遍的内容我们继续说说workLoop是如何将每一个组件的函数渲染成Fiber树的。
LamHo
2022/09/26
3350
小前端读源码 - React16.7.0(四)
React源码解读 【三】任务调度
•微信公众号 《JavaScript全栈》•掘金 《合一大师》•Bilibili 《合一大师》•源码Github地址:https://github.com/Walker-Leee/react-learn-code-v16.12.0
合一大师
2020/07/20
8370
React源码解读 【三】任务调度
React源码解析之FunctionComponent(中)
作用: 当子节点不为 null,则复用子节点并删除其兄弟节点; 当子节点为 null,则创建新的 fiber 节点
进击的小进进
2019/12/02
6030
React源码解析之workLoop
在React源码解析之renderRoot概览中,提到了renderRoot()会调用 workLoop()/workLoopSync() 进行循环单元的更新:
进击的小进进
2019/11/18
1.4K0
相关推荐
React.forwardRef的应用场景及源码解析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验