10

前言

上一篇写了Children,createRef,接着上一篇写后面的几个API

React-API

const React = {
  Children: {
    map,
    forEach,
    count,
    toArray,
    only,
  },

  createRef,
  Component,
  PureComponent,

  createContext,
  forwardRef,
  lazy,
  memo,

  useCallback,
  useContext,
  useEffect,
  useImperativeHandle,
  useDebugValue,
  useLayoutEffect,
  useMemo,
  useReducer,
  useRef,
  useState,

  Fragment: REACT_FRAGMENT_TYPE,
  Profiler: REACT_PROFILER_TYPE,
  StrictMode: REACT_STRICT_MODE_TYPE,
  Suspense: REACT_SUSPENSE_TYPE,

  createElement: createElement,
  cloneElement:  cloneElement,
  createFactory: createFactory,
  isValidElement: isValidElement,

  version: ReactVersion,

  __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals,
};

Component

const emptyObject = {};

class Component {
  constructor(props, context, updater) {
    this.props = props;
    this.context = context;
    this.ref = emptyObject;
    this.updater = updater || null;
  }
  isReactComponent() {}

  setState(partialState, callback) {
    this.updater.enqueueSetState(this, partialState, callback, "setState");
  }
  forceUpdate(callback) {
    this.updater.enqueueForceUpdate(this, callback, "forceUpdate");
  }
}

这里我稍微改了一下源代码,源代码是用的function构造函数,这里我觉的class看着会更简单一些,其实是一摸一样的,Component的源代码在ReactBaseClasses里

  • 这块代码比较简单,先创建一个Component类,可接收props,context,updater三个参数
  • 并分赋值

    • this.props = props;
    • this.context = context;
    • this.ref = emptyObject;
    • this.updater = updater || null;
  • isReactComponent: 没什么特别意义,在react-dom包中会有一些地方拿原型中是否存在这个方法来判断是不是一个class Component
  • setState:调用了this.updater.enqueueSetState,这个方法主就是setState的主要逻辑,放到react-dom中再去说,它在ReactFiberClassComponent中注入
  • forceUpdate:跟setState一样调用了this.updater中的方法enqueueForceUpdate

补充一下源码中可能用到了ReactNoopUpdateQueue,这个文件只是在dev中使用,仅仅给出一些提示而已

PureComponent

class PureComponent extends Component {
  constructor(props, context, updater) {
    super(props, context, updater);
    this.props = props;
    this.context = context;
    this.refs = emptyObject;
    this.updater = updater || null;
  }

  isPureReactComponent = true;
}
  • PureComponent和Component一摸一样,仅仅只是多了一个标志属性isPureReactComponent = true

createContext

import { REACT_CONTEXT_TYPE, REACT_PROVIDER_TYPE } from "shared/ReactSymbols";

export function createContext(defaultValue, calculateChangedBits) {
  if (calculateChangedBits == undefined) {
    calculateChangedBits = null;
  }

  const context = {
    $$typeof: REACT_CONTEXT_TYPE,
    _calculateChangedBits: calculateChangedBits,
    _currentValue: defaultValue,
    _currentValue2: defaultValue,
    _threadCount: 0,
    Provider: null,
    Consumer: null
  };

  (context.Provider = {
    $$typeof: REACT_PROVIDER_TYPE,
    _context: context
  }),
    (context.Consumer = context);

  return context;
}
  • 这个方法可以简单的看就是返回一个对象,而对象中的内容就是以上这么几项,唯一值的关注的是Provider和Consumer
  • Provider 的属性是一个$$typeof: REACT_PROVIDER_TYPE,一个symbol标志位,react中很多对象都会有这样一个唯一的symbol属性,只是为了提供在react-dom中做更新操作的时候能更好的区分和判断类型
  • Concumer:把context整个对象都赋值给了它
  • 最后返回一个context
  • 官方的API好像没有第二个参数calculateChangedBits,这个参数传是一个(oldValue,newValue)=> number, 用来计算新老context的值,这个也是react-dom的内容,提前有兴趣可以看ReactFiberNewContext这个文件

forwardRef

import { REACT_FORWARD_REF_TYPE } from "shared/ReactSymbols";

export default function forwardRef(render) {
  return {
    $$typeof: REACT_FORWARD_REF_TYPE,
    render
  };
}
  • 和createRef这样的API差不多就是返回一个对象,给一个symbol唯一属性,react中有很多这样的API,最终在createElement的时候会把这个对象挂在type当中

lazy

import { REACT_LAZY_TYPE } from "shared/ReactSymbols";

export function lazy(ctor) {
  let lazyType = {
    $$typeof: REACT_LAZY_TYPE,
    // then方法
    _ctor: ctor,
    // 记录当前状态 pending,resolve,reject
    _status: -1,
    // resolve 后返回的属性
    _result: null
  };

  return lazyType;
}
  • lazy方法也是返回一个对象
  • $$typeof 还是一个symbol
  • _ctor等于的是一个传入的ctor,也就是一个then函数,promise
  • _status: 记录的是当前家在的状态,pending,resolve,reject
  • _result: 会记录ctor这个函数最终返回的结果

memo

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,
  };
}
  • $$typeof: symbol
  • type: 传入的一个function component
  • compare:一个函数,对新老属性做对比,返回true | false

hooks

function resolveDispatcher() {
  const dispatcher = ReactCurrentDispatcher.current;
  return dispatcher;
}

export function useContext(Context, unstable_observedBits) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useContext(Context, unstable_observedBits);
}

export function useState(initialState) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useState(initialState);
}

export function useReducer(reducer, initialArg, init) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useReducer(reducer, initialArg, init);
}

export function useRef(initialValue) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useRef(initialValue);
}

export function useEffect(create, inputs) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useEffect(create, inputs);
}

export function useLayoutEffect(create, inputs) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useLayoutEffect(create, inputs);
}

export function useCallback(callback, inputs) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useCallback(callback, inputs);
}

export function useMemo(create, inputs) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useMemo(create, inputs);
}

export function useImperativeHandle(ref, create, inputs) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useImperativeHandle(ref, create, inputs);
}

export function useDebugValue(value, formatterFn) {
  if (__DEV__) {
    const dispatcher = resolveDispatcher();
    return dispatcher.useDebugValue(value, formatterFn);
  }
}

export const emptyObject = {};

export function useResponder(responder, listenerProps) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useResponder(responder, listenerProps || emptyObject);
}

export function useTransition(config) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useTransition(config);
}

export function useDeferredValue(value, config) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useDeferredValue(value, config);
}
  • 我删除了一些dev环境中使用的代码,整体看上去其实在这个包中处理的没什么区别,都是先获取dispatcher,然后调用了dispatcher中对应的hooks方法

Fragment

Profiler

StrictMode

Suspense

  Fragment: REACT_FRAGMENT_TYPE,
  Profiler: REACT_PROFILER_TYPE,
  StrictMode: REACT_STRICT_MODE_TYPE,
  Suspense: REACT_SUSPENSE_TYPE,
  • 上面四个API都仅仅只是一个symbol没什么好说的
  • Profiler可能用的比较少,他是获取一个fiber更新时间的
  • StrictMode是用来包裹组件,以获取一些过期API警告,不安全的生命周期警告之类的吧
  • Suspense就是个异步组件加载前的一个展示吧。

可能很多人看了很疑惑,感觉看完也没什么用,但这就是一个看react源码的逻辑,不要一开始就过分追求从到到尾的实现,因为react代码很多很多,我觉得一层一层的往里看是比较好的方法,等看完这些,到了react-dom内容的时候,慢慢的就会发现这些API里面的属性它到底是做什么用的了。

补充:
今天重新编辑了文章,补充了几个API,其实讲到这里其实差不多了,还剩几个ReactElement里的API,那几个API应该很多人都了解过,我放到下一篇写好了。认真看到这里的话,其实会发现这个包里并没有什么难的,而且大部分API都差不多,另外或许也能猜到这些API大部分都是通过一个$$typeof的唯一标识,提供react-dom做判断,来做不同的处理,这也是react的设计方式之一,规避了不同平台的兼容性


accord
1.3k 声望187 粉丝

希望遇到一个公司,遇到一个团队,大家都愿意把code当作一种艺术去书写