Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
276 lines (219 sloc) 8.08 KB
  1. ReactCreateRef.js
  2. ReactContext.js
  3. ReactLazy.js
  4. forwardRef.js
  5. memo.js

ReactCreateRef.js

使用方法见Refs 和 DOM

定义createRef函数,返回一个具备current属性的refObject对象。

export function createRef(): RefObject {
  const refObject = {
    current: null,
  };
  if (__DEV__) {
    Object.seal(refObject);
  }
  return refObject;
}

ReactLazy.js

使用方法见React.lazy

React.lazy() 允许你定义动态加载的组件。 这有助于减少包大小,以延迟加载在初始渲染期间未使用的组件。

const SomeComponent = React.lazy(() => import('./SomeComponent'));

定义一个Lazy函数,传入一个函数,返回一个对象,其_ctor中为动态加载逻辑包含需要懒加载组件调的位置,$$typeof: 为REACT_LAZY_TYPE组件类型

export function lazy<T, R>(ctor: () => Thenable<T, R>): LazyComponent<T> {
  return {
    $$typeof: REACT_LAZY_TYPE, //REACT_LAZY_TYPE组件类型
    _ctor: ctor, //动态加载逻辑
    // React uses these fields to store the result.
    _status: -1,
    _result: null,
  };
}

memo.js

什么是React.memo

组件仅在它的 props 发生改变的时候进行重新渲染。通常来说,在组件树中 React 组件,只要有变化就会走一遍渲染流程。但是通过 PureComponent 和 React.memo(),我们可以仅仅让某些组件进行渲染。React.memo 是一个高阶组件。 它与 React.PureComponent 类似,但是他用于包裹函数式组件,而不是类组件。

返回一个对象:

 {
    $$typeof: REACT_MEMO_TYPE,//组件类型
    type,//传入的函数组件
    compare: compare === undefined ? null : compare,//用于控制是否重新渲染的函数
  }

export default function memo<Props>(
  type: React$ElementType,
  compare?: (oldProps: Props, newProps: Props) => boolean,
) {
  if (__DEV__) {
    if (!isValidElementType(type)) {
      warningWithoutStack(
        false,
        'memo: The first argument must be a component. Instead ' +
          'received: %s',
        type === null ? 'null' : typeof type,
      );
    }
  }
  return {
    $$typeof: REACT_MEMO_TYPE,
    type,
    compare: compare === undefined ? null : compare,
  };
}

forwardRef.js

React.forwardRef 接受一个渲染函数(ts中不允许传入一个类组件,其他情况下能传入某些类组件),该函数接收 props 和 ref 参数并返回一个 React 节点。可以用于解决:添加一个 ref 到 HOC , 这个 ref 将引用最外面的容器组件,而不是包裹的组件。


返回一个对象:

  return {
    $$typeof: REACT_FORWARD_REF_TYPE,
    render,
  };

传入的渲染函数的参数问题

只有在传入两个参数或者不传参数的时候,不会报错。传一个参数或者传入多于两个参数会报错


与memo组合使用

在与memo组合使用的时候,应该是如下方式:

memo(forwardRef(...))

不能是:

forwardRef(memo(...))

因为根据memo.js,memo返回的是一个对象而不是一个渲染函数。

渲染函数不允许有defaultProps与propTypes

defaultProps定义默认的props:

MyComponent.defaultProps = {
  color: 'blue'
};

propTypes规定传入的props的内型:

MyComponent.propTypes = {optionalArray: PropTypes.array,...}

特别需要注意的是

尽量不要传入类组件,当在ts中的时候,需要对props进行类型规定,因此propTypes不会是null,此时会报错:Did you accidentally pass a React component?


export default function forwardRef<Props, ElementType: React$ElementType>(
  render: (props: Props, ref: React$Ref<ElementType>) => React$Node,
) {
  if (__DEV__) {
    if (render != null && render.$$typeof === REACT_MEMO_TYPE) {
      warningWithoutStack(
        false,
        'forwardRef requires a render function but received a `memo` ' +
          'component. Instead of forwardRef(memo(...)), use ' +
          'memo(forwardRef(...)).',
      );
    } else if (typeof render !== 'function') {
      warningWithoutStack(
        false,
        'forwardRef requires a render function but was given %s.',
        render === null ? 'null' : typeof render,
      );
    } else {
      warningWithoutStack(
        // Do not warn for 0 arguments because it could be due to usage of the 'arguments' object
        render.length === 0 || render.length === 2,
        'forwardRef render functions accept exactly two parameters: props and ref. %s',
        render.length === 1
          ? 'Did you forget to use the ref parameter?'
          : 'Any additional parameter will be undefined.',
      );
    }

    if (render != null) {
      warningWithoutStack(
        render.defaultProps == null && render.propTypes == null,
        'forwardRef render functions do not support propTypes or defaultProps. ' +
          'Did you accidentally pass a React component?',
      );
    }
  }

  return {
    $$typeof: REACT_FORWARD_REF_TYPE,
    render,
  };
}

ReactContext.js

传入的参数为:

defaultValue,provider提供的默认值
calculateChangedBits,函数

定义context:

const context: ReactContext<T> = {
    $$typeof: REACT_CONTEXT_TYPE,
    _calculateChangedBits: calculateChangedBits,
    _currentValue: defaultValue,
    _currentValue2: defaultValue,
    // These are circular
	// 循环引用
    Provider: (null: any),
    Consumer: (null: any),
  };

定义context.Provider:

context.Provider = {
    $$typeof: REACT_PROVIDER_TYPE,
    _context: context,//引用context
  };

生产环境下定义context.Consumer = context

开发模式下定义context.Consumer = Consumer:

const Consumer = {
      $$typeof: REACT_CONTEXT_TYPE,
      _context: context,
      _calculateChangedBits: context._calculateChangedBits,
    };

源码如下:

Object.defineProperties(Consumer, {
      Provider: {
        get() {
          if (!hasWarnedAboutUsingConsumerProvider) {
            hasWarnedAboutUsingConsumerProvider = true;
            warning(
              false,
              'Rendering <Context.Consumer.Provider> is not supported and will be removed in ' +
                'a future major release. Did you mean to render <Context.Provider> instead?',
            );
          }
          return context.Provider;
        },
        set(_Provider) {
          context.Provider = _Provider;
        },
      },
      _currentValue: {
        get() {
          return context._currentValue;
        },
        set(_currentValue) {
          context._currentValue = _currentValue;
        },
      },
      _currentValue2: {
        get() {
          return context._currentValue2;
        },
        set(_currentValue2) {
          context._currentValue2 = _currentValue2;
        },
      },
      Consumer: {
        get() {
          if (!hasWarnedAboutUsingNestedContextConsumers) {
            hasWarnedAboutUsingNestedContextConsumers = true;
            warning(
              false,
              'Rendering <Context.Consumer.Consumer> is not supported and will be removed in ' +
                'a future major release. Did you mean to render <Context.Consumer> instead?',
            );
          }
          return context.Consumer;
        },
      },
    });

在使用Context.Consumer.Provider获取值得时候:

Context.Consumer.Provider会被替换成: Context.Provider,这两者等价

		get() {
          return context.Provider;
        },

Context.Consumer.Consumer会被替换成:Context.Consumer,这两者等价

	get() {
      return context.Consumer;
    },

对Context.Consumer.Provider重新赋值,可以替换context.Provider:

        set(_Provider) {
          context.Provider = _Provider;
        }

对Context.Consumer.Consumer重新赋值,不会替换context.Consumer

You can’t perform that action at this time.