React 源码解析之总览

栏目: 服务器 · 发布时间: 5年前

内容简介:排版本小书的 React 版本是先说下 React16 这个版本节点吧。React16 较之前的版本是核心上的一次重写(想想就疯狂),虽然之前 API 没有变化继续使用,但同时也增加了很多好用的功能(不然不是白瞎了么)。这也是首次引入

排版本小书的 React 版本是 V16.8.6

先说下 React16 这个版本节点吧。

React16 较之前的版本是核心上的一次重写(想想就疯狂),虽然之前 API 没有变化继续使用,但同时也增加了很多好用的功能(不然不是白瞎了么)。这也是首次引入 Fiber 概念,之后新的功能都是围绕 Fiber ,比如 AsyncModeProfiler 等。

说明:后面章节贴代码的部分,我都会删除原来英文注释,加上自己的理解,有问题的地方,还请在评论中指出(如果有评论的话,没有评论可以加我,有朋自远方来...)

V16.8.6 代码

看看截止目前为止,React 暴露出来的 API

// react-16.8.6/packages/react/index.js
'use strict';
const React = require('./src/React');
module.exports = React.default || React;

// react-16.8.6/packages/react/src/React.js
...

const React = {
  // packages/react/src/ReactChildren.js
  Children: {
    map,
    forEach,
    count,
    toArray,
    only,
  },

  // packages/react/src/ReactCreateRef.js
  createRef,
  // packages/react/src/ReactBaseClasses.js
  Component,
  PureComponent,

  // packages/react/src/ReactContext.js
  createContext,
  // packages/react/src/forwardRef.js
  forwardRef,
  lazy,
  memo,

  // packages/react/src/ReactHooks.js
  useCallback,
  useContext,
  useEffect,
  useImperativeHandle,
  useDebugValue,
  useLayoutEffect,
  useMemo,
  useReducer,
  useRef,
  useState,

  // packages/shared/ReactSymbols.js
  Fragment: REACT_FRAGMENT_TYPE,
  StrictMode: REACT_STRICT_MODE_TYPE,
  Suspense: REACT_SUSPENSE_TYPE,

  // packages/react/src/ReactElementValidator.js
  createElement: __DEV__ ? createElementWithValidation : createElement,
  cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
  createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
  isValidElement: isValidElement,

  // packages/shared/ReactVersion.js
  version: ReactVersion,

  // packages/shared/ReactSymbols.js
  unstable_ConcurrentMode: REACT_CONCURRENT_MODE_TYPE,
  unstable_Profiler: REACT_PROFILER_TYPE,

  // packages/react/src/ReactSharedInternals.js
  __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals,
};

...
复制代码

上面代码我们选择性的去解析,无需所有都要去了解(个人学习方法方式)。

先说 Children

这个对象提供了一些处理 props.children 方法, children 是一个类似数组但又不是数组的数据结构,对其进行处理时可用 React.Children 外挂方法。

createRef

ref 用法,不推荐使用 string ref 用法,比如 <div ref="divRef" /> 。那正确姿势是怎样的呢?请看

class App extends React.Component {
  constructor() {
    this.ref = React.createRef();
  }

  render() {
    return <div ref={this.ref} />
    // or
    return <div ref={node => this.ref = node} />
  }
}
复制代码

ComponentPureComponent

packages/react/src/ReactBaseClasses.js 代码

// Component
function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}

Component.prototype.isReactComponent = {};
Component.prototype.setState = function(partialState, callback) {}
Component.prototype.forceUpdate = function(callback) {}

// ComponentDummy => Component仿制品
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;

// PureComponent
function PureComponent(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true; // 多了一个标识

export { Component, PureComponent };
复制代码

这两个类基本相同,唯一区别是 PureComponent 的原型上多了一个标识 isPureReactComponent

if (ComponentExample.prototype && ComponentExample.prototype.isPureReactComponent) {
  return (
    !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
  );
}
复制代码

这是检查组件是否需要更新的一个判断, ComponentExample 是你声明的继承自 ComponentPureComponent 的类,他会判断你是否继承自 PureComponent ,如果是的话就用 shallowEqual 比较 stateprops

By the way(顺便说一下,允许我骚一下):React 中对比一个 ClassComponent 是否需要更新,只有两个地方。

一是看有没有 shouldComponentUpdate 方法;二就是这里的 PureComponent 判断;

createContext

createContext 是官方定稿的 context 方案,在这之前我们一直在用的老的 context API ,也是 React 不推荐的 API 。Now(现在),新的 API 出来了,官方也已经确定在 17 大版本会把老 API 去除。

新 API 的使用方法

const { Provider, Consumer } = React.createContext('defaultValue');

const ProviderComp = props => (
  <Provider value='realValue'>
    {props.children}
  </Provider>
);

const ConsumerComp = () => (
  <Consumer>
    {value => <p>{value}</p>}
  </Consumer>
)
复制代码

具体差异,后面讲 context 环节会详细指出。

forwardRef

forwardRef 是用来解决 HOC 组件传递 ref 的问题的,所谓 HOC 就是 Higher Order Component 。就拿 redux 来说,使用 connect 来给组件绑定需要的 state ,这其中其实就是给我们的组件在外部包了一层组件,然后通过 ...props 的方式把外部的 props 传入到实际组件。 forwardRef 的使用方法如下:

const TargetComponent = React.forwordRef((props, ref) => {
  <TargetComponent ref={ref} {...props} />
});
复制代码

这也说明了为什么要提供 createRef 作为新的 ref 使用方法的原因,如果用 string ref 就没法当作参数传递了。

后面章节会详细分析 ref

lazy

是用来实现异步加载模块的功能。

memo

是一个高阶函数,它与 React.PureComponent类似,但是一个函数组件而非一个类。

useXXX 系列

这就是 React16 的 Hooks 了,后续会做代码分解。

类型

Fragment: REACT_FRAGMENT_TYPE,
StrictMode: REACT_STRICT_MODE_TYPE,
Suspense: REACT_SUSPENSE_TYPE,
unstable_ConcurrentMode: REACT_CONCURRENT_MODE_TYPE,
unstable_Profiler: REACT_PROFILER_TYPE,
复制代码

这 5 个都是 React 提供的组件,但他们呢其实都只是 占位符 ,都是一个 Symbol ,在 React 实际检测到他们的时候会做一些特殊的处理,比如 StrictModeAsyncMode 会让他们的子节点对应的 Fiber 的 mode 都变成和他们一样的 mode

元素

createElement: __DEV__ ? createElementWithValidation : createElement,
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
isValidElement: isValidElement,
复制代码

createElement

是 React 输出中最重要的 API 了,是用来创建 ReactElement 的,但是很多前端童鞋却从没见过,也没用过,这是为什么呢?这就得感谢 JSX 了,我们知道 JSX 并不是标准的 js,所以要经过编译才能变成可运行的 js,而编译之后, createElement 就出现了:

// jsx
<div id="app">content</div>

// js
React.createElement('div', { id: 'app' }, 'content')
复制代码

cloneElement

它就很明显了,是用来克隆一个 ReactElement

createFactory

它是用来创建专门用来创建某一类 ReactElement 的工厂的

export function createFactory(type) {
  const factory = createElement.bind(null, type);
  factory.type = type;
  return factory;
}
复制代码

其实就是绑定了第一个参数的 createElement ,一般我们用 JSX 进行编程的时候不会用到这个 API。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

New Dark Age

New Dark Age

James Bridle / Verso Books / 2018-7-17 / GBP 16.99

As the world around us increases in technological complexity, our understanding of it diminishes. Underlying this trend is a single idea: the belief that our existence is understandable through comput......一起来看看 《New Dark Age》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具