React源码解析之 API简介

847 阅读6分钟

这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战

作为一个程序员,还是看代码说话吧!

const Children = {
  map,
  forEach,
  count,
  toArray,
  only,
};

export {
  Children,
  createMutableSource,
  createRef,
  Component,
  PureComponent,
  createContext,
  forwardRef,
  lazy,
  memo,
  useCallback,
  useContext,
  useEffect,
  useImperativeHandle,
  useDebugValue,
  useLayoutEffect,
  useMemo,
  useMutableSource,
  useReducer,
  useRef,
  useState,
  REACT_FRAGMENT_TYPE as Fragment,
  REACT_PROFILER_TYPE as Profiler,
  REACT_STRICT_MODE_TYPE as StrictMode,
  REACT_DEBUG_TRACING_MODE_TYPE as unstable_DebugTracingMode,
  REACT_SUSPENSE_TYPE as Suspense,
  createElement,
  cloneElement,
  isValidElement,
  ReactVersion as version,
  ReactSharedInternals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
  // Deprecated behind disableCreateFactory
  createFactory,
  // Concurrent Mode
  useTransition,
  startTransition,
  useDeferredValue,
  REACT_SUSPENSE_LIST_TYPE as SuspenseList,
  REACT_LEGACY_HIDDEN_TYPE as unstable_LegacyHidden,
  REACT_OFFSCREEN_TYPE as unstable_Offscreen,
  getCacheForType as unstable_getCacheForType,
  useCacheRefresh as unstable_useCacheRefresh,
  REACT_CACHE_TYPE as unstable_Cache,
  // enableScopeAPI
  REACT_SCOPE_TYPE as unstable_Scope,
  useOpaqueIdentifier as unstable_useOpaqueIdentifier,
  act,
};

上述代码,就是 ReactV17.0.2版本抛出的所有的最新的API,也就是说在项目书写中上述所有的API都可以使用 React.API名称的形式调用

class类组件中的一些API

Children

  • 该对象提供了一堆帮助你处理 props.children的方法,具体的有 map,forEach,count,toArray,only五个。
  • 之所以需要这些处理方法,是因为在组件的props.children是一个类数组,不能使用数组常规的方法,此时如果你需要对其进行处理的话就可以通过 React.Children上外挂的方法。

createMutableSource

  • 顾名思义 就是 创建可变的资源。 (貌似是在v18版本的提案中)

createRef

  • React.createRef 创建一个能够通过 ref 属性附加到 React 元素的ref
class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();  }

  render() {
    return <input type="text" ref={this.inputRef} />;  }

  componentDidMount() {
    this.inputRef.current.focus();  }
}

forwardRef

  • React.forwardRef 会创建一个React组件,这个组件能够将其接受的ref 属性转发到其组件树下的另一个组件中。常用于下面两种场景:
    • 转发 refs 到 DOM 组件
    • 在高阶组件中转发refs
  • React.forwardRef 接受渲染函数作为参数。React 将使用 props 和 ref 作为参数来调用此函数。此函数应返回 React 节点。
const FancyButton = React.forwardRef((props, ref) => {
    return  (  
        <button ref={ref} className="FancyButton">    
            {props.children}
        </button>
    )
});

const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

在上述的示例中,React 会将 <FancyButton ref={ref}> 元素的 ref 作为第二个参数传递给 React.forwardRef 函数中的渲染函数。该渲染函数会将 ref 传递给 <button ref={ref}> 元素。

因此,当 React 附加了 ref 属性之后,ref.current 将直接指向 <button> DOM 元素实例。

Component & PureComponent

  • 两者都是用来创建自定义的组件,唯一的区别是 PureComponent 可以对组件更新进行一定程度的优化。

createContext

  • 主要是用于 祖先组件 和 后代组件之间的传值。解决多层嵌套组件传递值时层层传递的问题。
  • React.createContext 创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。
  • 具体使用方法,查看官网Context

createElement & cloneElement & createFactory & isValidElement

  • createElement 用来创建react元素,该方法接收三个参数。
  • cloneElement 用来clone一个react元素。
  • createFactory 用来创建某一类的 reactElement的工厂。
  • isValidElement 用来检验是否是一个reactElement类型。

memo

  • memo为高阶组件。与 React.PureComponent 非常相似,但是只适用于函数组件
  • memo 仅检查props的变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useState 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染。
  • 也就是说memo对 hooks写法的函数组件 无效。
  • 默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

lazy

  • React.lazy() 允许你定义一个动态加载的组件。这有助于缩减 bundle 的体积,并延迟加载在初次渲染时未用到的组件。(通常用来做代码分割,实现懒加载)
const SomeComponent = React.lazy(() => import('./SomeComponent'));
  • 渲染 lazy 组件依赖该组件渲染树上层的 <React.Suspense> 组件。这是指定加载指示器(loading indicator)的方式。

Suspense

  • React.Suspense 可以指定加载指示器(loading indicator),以防其组件树中的某些子组件尚未具备渲染条件。
  • 目前,懒加载组件是 <React.Suspense> 支持的唯一用例:
  • lazy 组件可以位于 Suspense 组件树的深处,它不必包装树中的每一个延迟加载组件。 注意: 目前来说,React.lazy() 和 <React.Suspense> 尚未在 ReactDOMServer 中支持

hooks中的一些API

  • useState 该方法返回一个state 以及更新state的函数。并且可以传入第一个参数作为state的初始值。
  • useEffect 该 Hook 接收一个包含命令式、且可能有副作用代码的函数。
  • 赋值给 useEffect 的函数会在组件渲染到屏幕之后执行
  • 默认情况下,useEffect 将在每轮渲染结束后执行,但你可以选择让它 在只有某些值改变的时候才执行。
  • useEffect 函数如果返回一个函数,则该返回的函数会在组件卸载之前执行。如果组件多次渲染的话,则会在执行下一个 effect 之前,上一个effect 就已经被清除。
  • useEffect 接收第二个参数(数组),如果是空数组则相当于 componentDidMount 和 componentWillUnmount,只会执行一次。

useContext

  • 相当于class组件中的 React.createContext 的用法。

useReducer

  • useState的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。

useCallback

  • 把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新
  • 依赖项数组不会作为参数传递给回调函数。
  • useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

useMemo

  • 把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
  • 传入 useMemo 的函数会在**渲染期间执行**
  • 如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值

useRef

  • useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变注意:
  • 当 ref 对象内容发生变化时,useRef 并不会通知你。
  • 变更 .current 属性不会引发组件重新渲染
  • 如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。

useImperativeHandle

  • useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用

useLayoutEffect

  • 其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect
  • 可以使用它来读取 DOM 布局并同步触发重渲染。
  • 在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

useDebugValue

  • useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。