React.forwardRef 和 React.lazy

1. React.forwardRef

React.forwardRef会创建一个React组件,这个组件能够将其接受的ref属性转发到其组件树下的另一个组件中。

这种情况并不常见,但是对于如下的场景尤其适用:

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

对于FancyButton这个组件,我们可以把它看作一个按钮的高级封装,有时我们希望这个组件可以像操纵原生button(获取焦点,获取value)DOM那样被我们控制。

Ref转发允许我们给某些组件赋予ref,并将其向下传递给子组件。

再考虑上面的代码,具体流程是这样的:

  1. 调用React.createRef创建一个React ref并交给变量ref。
  2. 把这个变量ref交给 FancyButton组件。
  3. 观察FancyButton组件,可以看到React.forwardRef接受的第二个参数ref,组件内ref向下传递给了button。
  4. 当ref挂载完成时,ref.current将指向button的DOM节点。

注意

第二个参数 ref 只在使用 React.forwardRef 定义组件时存在。常规函数和 class 组件不接收 ref 参数,且 props 中也不存在 ref

Ref 转发不仅限于 DOM 组件,你也可以转发 refs 到 class 组件实例中。


2. React.Lazy

React.lazy() 允许你定义一个动态加载的组件。这有助于缩减 bundle 的体积,并延迟加载在初次渲染时未用到的组件。

渲染 lazy 组件依赖该组件渲染树上层的 <React.Suspense> 组件。这是指定加载指示器(loading indicator)的方式。

Just like this:

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

React.Suspense 可以指定加载指示器(loading indicator),以防其组件树中的某些子组件尚未具备渲染条件。

// 该组件是动态加载的
const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    // 显示 <Spinner> 组件直至 OtherComponent 加载完成
    <React.Suspense fallback={<Spinner />}>
      <div>
        <OtherComponent />
      </div>
    </React.Suspense>
  );
}

请注意,lazy 组件可以位于 Suspense 组件树的深处——它不必包装树中的每一个延迟加载组件。最佳实践是将<Suspense>置于你想展示加载指示器(loading indicator)的位置,而 lazy() 则可被放置于任何你想要做代码分割的地方。