直接进入主题
首先我们看下,版本 17.0.1

  1. export {
  2. Children,
  3. createRef,
  4. Component,
  5. PureComponent,
  6. createContext,
  7. forwardRef,
  8. lazy,
  9. memo,
  10. useCallback,
  11. useContext,
  12. useEffect,
  13. useImperativeHandle,
  14. useDebugValue,
  15. useLayoutEffect,
  16. useMemo,
  17. useReducer,
  18. useRef,
  19. useState,
  20. useMutableSource,
  21. useMutableSource as unstable_useMutableSource,
  22. createMutableSource,
  23. createMutableSource as unstable_createMutableSource,
  24. Fragment,
  25. Profiler,
  26. unstable_DebugTracingMode,
  27. StrictMode,
  28. Suspense,
  29. createElement,
  30. cloneElement,
  31. isValidElement,
  32. version,
  33. __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
  34. createFactory,
  35. useTransition,
  36. useTransition as unstable_useTransition,
  37. startTransition,
  38. startTransition as unstable_startTransition,
  39. useDeferredValue,
  40. useDeferredValue as unstable_useDeferredValue,
  41. SuspenseList,
  42. SuspenseList as unstable_SuspenseList,
  43. block,
  44. block as unstable_block,
  45. unstable_LegacyHidden,
  46. unstable_createFundamental,
  47. unstable_Scope,
  48. unstable_useOpaqueIdentifier,
  49. } from './src/React';

Children

  1. export {
  2. forEachChildren as forEach,
  3. mapChildren as map,
  4. countChildren as count,
  5. onlyChild as only,
  6. toArray,
  7. };

对象提供了一堆帮你处理props.children的方法,因为children是一个类似数组但是不是数组的数据结构,如果你要对其进行处理可以用React.Children外挂的方法

Component&&PureComponent

这两个类基本上没太大差别都是基本类,PureReactComponent 多了一个isPureReactComponent属性。

  1. const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
  2. pureComponentPrototype.constructor = PureComponent;
  3. // Avoid an extra prototype jump for these methods.
  4. Object.assign(pureComponentPrototype, Component.prototype);
  5. pureComponentPrototype.isPureReactComponent = true;

这是检查组件是否需要更新的一个判断,ctor就是你声明的继承自Component or PureComponent的类,他会判断你是否继承自PureComponent,如果是的话就shallowEqual比较stateprops
顺便说一下:React中对比一个ClassComponent是否需要更新,只有两个地方。一是看有没有shouldComponentUpdate方法,二就是这里的PureComponent判断

Fragment

一个空节点,包裹所有的兄弟节点, 可以使用<> 代替

  1. render(){
  2. return (
  3. <>
  4. <span>test</span>
  5. </>
  6. )
  7. }
  8. render(){
  9. return (
  10. <React.Fragment>
  11. <span>test</span>
  12. </React.Fragment>
  13. )
  14. }
  15. render(){
  16. return (
  17. <React.Fragment key={ddd}>
  18. <span>test</span>
  19. </React.Fragment>
  20. )
  21. }

createElement & cloneElement & createFactory & isValidElement

createElement可谓是React中最重要的API了,他是用来创建ReactElement的,但是很多同学却从没见过也没用过,这是为啥呢?因为你用了JSX,JSX并不是标准的js,所以要经过编译才能变成可运行的js,而编译之后,createElement就出现了:

  1. // jsx
  2. <div id="app">content</div>
  3. // js
  4. React.createElement('div', { id: 'app' }, 'content')

cloneElement就很明显了,是用来克隆一个ReactElement
createFactory是用来创建专门用来创建某一类ReactElement的工厂的。

  1. export function createFactory(type) {
  2. const factory = createElement.bind(null, type);
  3. factory.type = type;
  4. return factory;
  5. }

他其实就是绑定了第一个参数的createElement,一般我们用JSX进行编程的时候不会用到这个API
isValidElement顾名思义就是用来验证是否是一个ReactElement的,基本也用不太到

Profiler

React 16.5 添加了对新的 profiler DevTools 插件的支持。这个插件使用 React 的 Profiler 实验性 API 去收集所有 component 的渲染时间,目的是为了找出你的 React App 的性能瓶颈。

Suspense

在 16.6 版本之前,code-spliting 通常是由第三方库来完成的,比如 react-loadble(核心思路为: 高阶组件 + webpack dynamic import), 在 16.6 版本中提供了 Suspenselazy 这两个钩子, 因此在之后的版本中便可以使用其来实现 Code Spliting

目前阶段, 服务端渲染中的 code-spliting 还是得使用 react-loadable, 可查阅 React.lazy, 暂时先不探讨原因。

Code SplitingReact 中的使用方法是在 Suspense 组件中使用 <LazyComponent> 组件:

  1. import { Suspense, lazy } from 'react'
  2. const DemoA = lazy(() => import('./demo/a'))
  3. const DemoB = lazy(() => import('./demo/b'))
  4. <Suspense>
  5. <NavLink to="/demoA">DemoA</NavLink>
  6. <NavLink to="/demoB">DemoB</NavLink>
  7. <Router>
  8. <DemoA path="/demoA" />
  9. <DemoB path="/demoB" />
  10. </Router>
  11. </Suspense>
  12. 复制代码

源码中 lazy 将传入的参数封装成一个 LazyComponent

  1. function lazy(ctor) {
  2. return {
  3. ?typeof: REACT_LAZY_TYPE, // 相关类型
  4. _ctor: ctor,
  5. _status: -1, // dynamic import 的状态
  6. _result: null, // 存放加载文件的资源
  7. };
  8. }
  9. 复制代码

观察 readLazyComponentType 后可以发现 dynamic import 本身类似 Promise 的执行机制, 也具有 PendingResolvedRejected 三种状态, 这就比较好理解为什么 LazyComponent 组件需要放在 Suspense 中执行了(Suspense 中提供了相关的捕获机制, 下文会进行模拟实现`), 相关源码如下:

  1. function readLazyComponentType(lazyComponent) {
  2. const status = lazyComponent._status;
  3. const result = lazyComponent._result;
  4. switch (status) {
  5. case Resolved: { // Resolve 时,呈现相应资源
  6. const Component = result;
  7. return Component;
  8. }
  9. case Rejected: { // Rejected 时,throw 相应 error
  10. const error = result;
  11. throw error;
  12. }
  13. case Pending: { // Pending 时, throw 相应 thenable
  14. const thenable = result;
  15. throw thenable;
  16. }
  17. default: { // 第一次执行走这里
  18. lazyComponent._status = Pending;
  19. const ctor = lazyComponent._ctor;
  20. const thenable = ctor(); // 可以看到和 Promise 类似的机制
  21. thenable.then(
  22. moduleObject => {
  23. if (lazyComponent._status === Pending) {
  24. const defaultExport = moduleObject.default;
  25. lazyComponent._status = Resolved;
  26. lazyComponent._result = defaultExport;
  27. }
  28. },
  29. error => {
  30. if (lazyComponent._status === Pending) {
  31. lazyComponent._status = Rejected;
  32. lazyComponent._result = error;
  33. }
  34. },
  35. );
  36. // Handle synchronous thenables.
  37. switch (lazyComponent._status) {
  38. case Resolved:
  39. return lazyComponent._result;
  40. case Rejected:
  41. throw lazyComponent._result;
  42. }
  43. lazyComponent._result = thenable;
  44. throw thenable;
  45. }
  46. }
  47. }

version

返回 React的Version,

createContext

创建一个上下文的容器(组件), defaultValue可以设置共享的默认数据
createContext是官方定稿的context方案,在这之前我们一直在用的老的context API都是React不推荐的API,现在新的API释出,官方也已经确定在17大版本会把老API去除。
新API的使用方法:

  1. const { Provider, Consumer } = React.createContext('defaultValue')
  2. const ProviderComp = (props) => (
  3. <Provider value={'realValue'}>
  4. {props.children}
  5. </Provider>
  6. )
  7. const ConsumerComp = () => (
  8. <Consumer>
  9. {(value) => <p>{value}</p>}
  10. </Consumber>
  11. )

后面讲context会专门比较新老的API的差异,提前说一句,老API的性能不是一般的差

createMutableSource

forwardRef

lazy

memo


reackhooks

useCallback,

useContext,

useEffect,

useImperativeHandle

useDebugValue

useLayoutEffect

useMemo

useReducer

useRef

useState

useMutableSource

useDeferredValue

useTransition

StrictMode

startTransition

SuspenseList

block

unstable_LegacyHidden

unstable_createFundamental

unstable_Scope

unstable_useOpaqueIdentifier

unstable_DebugTracingMode

block as unstable_block

useDeferredValue as unstable_useDeferredValue

useMutableSource as unstable_useMutableSource

useTransition as unstable_useTransition

startTransition as unstable_startTransition

SuspenseList as unstable_SuspenseList

createMutableSource as unstable_createMutableSource

__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED