- Children
- Component&&PureComponent
- Fragment
- createElement & cloneElement & createFactory & isValidElement
- Profiler
- Suspense
- version
- createContext
- createMutableSource
- forwardRef
- lazy
- memo
- reackhooks
- 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
直接进入主题
首先我们看下,版本 17.0.1
export {Children,createRef,Component,PureComponent,createContext,forwardRef,lazy,memo,useCallback,useContext,useEffect,useImperativeHandle,useDebugValue,useLayoutEffect,useMemo,useReducer,useRef,useState,useMutableSource,useMutableSource as unstable_useMutableSource,createMutableSource,createMutableSource as unstable_createMutableSource,Fragment,Profiler,unstable_DebugTracingMode,StrictMode,Suspense,createElement,cloneElement,isValidElement,version,__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,createFactory,useTransition,useTransition as unstable_useTransition,startTransition,startTransition as unstable_startTransition,useDeferredValue,useDeferredValue as unstable_useDeferredValue,SuspenseList,SuspenseList as unstable_SuspenseList,block,block as unstable_block,unstable_LegacyHidden,unstable_createFundamental,unstable_Scope,unstable_useOpaqueIdentifier,} from './src/React';
Children
export {forEachChildren as forEach,mapChildren as map,countChildren as count,onlyChild as only,toArray,};
对象提供了一堆帮你处理props.children的方法,因为children是一个类似数组但是不是数组的数据结构,如果你要对其进行处理可以用React.Children外挂的方法
Component&&PureComponent
这两个类基本上没太大差别都是基本类,PureReactComponent 多了一个isPureReactComponent属性。
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());pureComponentPrototype.constructor = PureComponent;// Avoid an extra prototype jump for these methods.Object.assign(pureComponentPrototype, Component.prototype);pureComponentPrototype.isPureReactComponent = true;
这是检查组件是否需要更新的一个判断,ctor就是你声明的继承自Component or PureComponent的类,他会判断你是否继承自PureComponent,如果是的话就shallowEqual比较state和props。
顺便说一下:React中对比一个ClassComponent是否需要更新,只有两个地方。一是看有没有shouldComponentUpdate方法,二就是这里的PureComponent判断
Fragment
一个空节点,包裹所有的兄弟节点, 可以使用<> 代替
render(){return (<><span>test</span></>)}render(){return (<React.Fragment><span>test</span></React.Fragment>)}render(){return (<React.Fragment key={ddd}><span>test</span></React.Fragment>)}
createElement & cloneElement & createFactory & isValidElement
createElement可谓是React中最重要的API了,他是用来创建ReactElement的,但是很多同学却从没见过也没用过,这是为啥呢?因为你用了JSX,JSX并不是标准的js,所以要经过编译才能变成可运行的js,而编译之后,createElement就出现了:
// jsx<div id="app">content</div>// 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进行编程的时候不会用到这个APIisValidElement顾名思义就是用来验证是否是一个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 版本中提供了 Suspense 和 lazy 这两个钩子, 因此在之后的版本中便可以使用其来实现 Code Spliting。
目前阶段, 服务端渲染中的
code-spliting还是得使用react-loadable, 可查阅 React.lazy, 暂时先不探讨原因。
Code Spliting 在 React 中的使用方法是在 Suspense 组件中使用 <LazyComponent> 组件:
import { Suspense, lazy } from 'react'const DemoA = lazy(() => import('./demo/a'))const DemoB = lazy(() => import('./demo/b'))<Suspense><NavLink to="/demoA">DemoA</NavLink><NavLink to="/demoB">DemoB</NavLink><Router><DemoA path="/demoA" /><DemoB path="/demoB" /></Router></Suspense>复制代码
源码中 lazy 将传入的参数封装成一个 LazyComponent
function lazy(ctor) {return {?typeof: REACT_LAZY_TYPE, // 相关类型_ctor: ctor,_status: -1, // dynamic import 的状态_result: null, // 存放加载文件的资源};}复制代码
观察 readLazyComponentType 后可以发现 dynamic import 本身类似 Promise 的执行机制, 也具有 Pending、Resolved、Rejected 三种状态, 这就比较好理解为什么 LazyComponent 组件需要放在 Suspense 中执行了(Suspense 中提供了相关的捕获机制, 下文会进行模拟实现`), 相关源码如下:
function readLazyComponentType(lazyComponent) {const status = lazyComponent._status;const result = lazyComponent._result;switch (status) {case Resolved: { // Resolve 时,呈现相应资源const Component = result;return Component;}case Rejected: { // Rejected 时,throw 相应 errorconst error = result;throw error;}case Pending: { // Pending 时, throw 相应 thenableconst thenable = result;throw thenable;}default: { // 第一次执行走这里lazyComponent._status = Pending;const ctor = lazyComponent._ctor;const thenable = ctor(); // 可以看到和 Promise 类似的机制thenable.then(moduleObject => {if (lazyComponent._status === Pending) {const defaultExport = moduleObject.default;lazyComponent._status = Resolved;lazyComponent._result = defaultExport;}},error => {if (lazyComponent._status === Pending) {lazyComponent._status = Rejected;lazyComponent._result = error;}},);// Handle synchronous thenables.switch (lazyComponent._status) {case Resolved:return lazyComponent._result;case Rejected:throw lazyComponent._result;}lazyComponent._result = thenable;throw thenable;}}}
version
createContext
创建一个上下文的容器(组件), defaultValue可以设置共享的默认数据createContext是官方定稿的context方案,在这之前我们一直在用的老的context API都是React不推荐的API,现在新的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>}</Consumber>)
后面讲context会专门比较新老的API的差异,提前说一句,老API的性能不是一般的差
