- 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>
// js
React.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 相应 error
const error = result;
throw error;
}
case Pending: { // Pending 时, throw 相应 thenable
const 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的性能不是一般的差