博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React 源码解析之总览
阅读量:6857 次
发布时间:2019-06-26

本文共 6078 字,大约阅读时间需要 20 分钟。

本小书大部分内容来自作者 Jokcy 的 《React 源码解析》:

本文已同步在我的博客:

感谢 Jokcy 让我深度了解 React。如他所说,在决定阅读 React 源码时认为不会是一件很难的事,但是真正开始阅读之后才发现,事情没那么简单,因为需要足够的耐心、能够独立思考和静下心来(因为你会碰到之前编码没有见过的写法和概念等等)。

平常我们对外(后端、产品或其他前端)总喜欢说用的是 React 框架,可是我们并都熟悉 React 内部是怎么运行的。事实上,当 Facebook 将 React 和 ReactDOM 分包发布后,React 就不仅仅是前端框架了,15版本后 react 源码越来越少,而 React-dom 却很大。很显然,react 的很多逻辑都移到 react-dom 中了。

版本说明

排版本小书的 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 
// or return
this.ref = node} /> }}复制代码

ComponentPureComponent

packages/react/src/ReactBaseClasses.js 代码

// Componentfunction 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;// PureComponentfunction 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 => (  
{props.children}
);const ConsumerComp = () => (
{value =>

{value}

}
)复制代码

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

forwardRef

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

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

这也说明了为什么要提供 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
content
// jsReact.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。

isValidElement

是用来验证是否是一个 ReactElement 的,基本也用不太到。

你还可以

转载于:https://juejin.im/post/5cc7d9be6fb9a032050e4c2f

你可能感兴趣的文章
我的友情链接
查看>>
自动化代码发布系统实现
查看>>
BAT 批处理脚本教程(如果可以用电脑让事情变的更简单,何不让它变得更简单呢!)...
查看>>
LInux系统基础
查看>>
zabbix监控Linux主机配置
查看>>
对Python进程进行全解析
查看>>
BOA+PHP在Tiny6410上的移植
查看>>
centos7.2 测试 FreeSwitch X-Lite (2)
查看>>
Msg 15581 Please create a master key in the database or open the master key in the session
查看>>
JAVA反射机制
查看>>
Log4j 2X 日志文件路径问题
查看>>
MySQL卸载及安装
查看>>
Ubuntu 11.04 下安装配置 JDK 7
查看>>
Linux下使用rsync最快速删除海量文件的方法。
查看>>
2015-2016寒假 第一、二周学习总结
查看>>
页面跳转 [转自: http://www.mamicode.com/info-detail-469709.html]
查看>>
linux系统文件管理与查找
查看>>
如何设计上十亿的用户表
查看>>
Scrum 冲刺博客第七篇
查看>>
Python 性能优化
查看>>