Skip to content

React 19 特性: ref 作为 prop 传递

在 React 19 中,ref 能够作为 prop 直接传递给函数组件,这是一个重要的更新,极大地优化了开发体验。在此之前,我们需要借助 forwardRef 这个高阶组件(HOC)来实现 ref 的转发,而现在这一过程变得更加直观和简洁。

我们来深入探讨这一变化带来的具体优势。

告别 forwardRef 的繁琐

在 React 19 之前,如果想将 ref 附加到我们自己封装的函数组件上,直接在 props 中传递是行不通的。React 会在内部处理 ref,并不会将其作为普通的 prop 传递下去。为了解决这个问题,我们必须使用 React.forwardRef

旧有的方式:使用 forwardRef

让我们看一个熟悉的例子:创建一个自定义的 MyInput 组件,并希望父组件能获取其底层 input 元素的引用。

javascript
import { forwardRef } from 'react';

const MyInput = forwardRef((props, ref) => {
  const { label, ...otherProps } = props;
  return (
    <label>
      {label}
      <input {...otherProps} ref={ref} />
    </label>
  );
});

// 使用
function MyForm() {
  const inputRef = useRef(null);

  function handleFocus() {
    inputRef.current.focus();
  }

  return (
    <>
      <MyInput ref={inputRef} label="Enter your name" />
      <button onClick={handleFocus}>Focus the input</button>
    </>
  );
}

这种写法的核心问题在于:

  1. 代码冗余:需要用 forwardRef 包裹整个组件。

  2. 心智负担:ref 是作为第二个参数传入的,这与常规的 props 对象分离,使得组件的签名不统一,增加了理解成本。

  3. 类型定义复杂:在 TypeScript 中,为使用了 forwardRef 的组件正确添加类型定义,往往需要处理复杂的泛型,例如 ForwardedRefRefForwardingComponent

React 19 的新方式:ref 即 prop

随着 React 19 的到来,ref 终于成为了“一等公民”,可以像其他任何 prop 一样直接传递。上面的 MyInput 组件可以被大大简化。

React 19 的方式:直接作为 prop 传递

javascript
// 无需引入 forwardRef
function MyInput({ label, ref, ...otherProps }) {
  return (
    <label>
      {label}
      <input {...otherProps} ref={ref} />
    </label>
  );
}

// 使用方式完全相同
function MyForm() {
  const inputRef = useRef(null);

  function handleFocus() {
    inputRef.current.focus();
  }

  return (
    <>
      <MyInput ref={inputRef} label="Enter your name" />
      <button onClick={handleFocus}>Focus the input</button>
    </>
  );
}

代码变得清晰直白,就像我们直觉上认为的那样工作。

核心优势总结

将 ref 作为 prop 直接传递,主要带来了以下几点优势:

  1. 代码更简洁,可读性更高 我们不再需要 forwardRef 的包裹。组件定义更加紧凑,逻辑也更聚焦于组件本身,而不是如何处理 ref 转发的模板代码。

  2. 降低心智负担,提升开发体验ref 只是 props 里的一个普通属性。这统一了组件的接口,开发者不再需要记忆 forwardRef 的特殊签名和用法。无论是初学者还是经验丰富的开发者,都能更快地编写和理解代码。

  3. 简化组件组合 当 ref 需要穿透多层组件时,优势尤为明显。每一层组件只需要简单地将 refprops 中取出再传递给下一层即可,不再需要层层嵌套 forwardRef,代码的整洁度大幅提升。

  4. 与 TypeScript 集成更友好ref prop 添加类型定义变得非常简单。我们可以像定义其他 prop 一样,直接在组件的 props 类型接口中声明 ref

javascript
import type { Ref } from 'react';

type MyInputProps = {
  label: string;
  ref: Ref<HTMLInputElement>;
  // 其他 props...
};

function MyInput({ label, ref, ...otherProps }: MyInputProps) {
  // ...
}

相比之下,forwardRef 的类型定义要繁琐得多,经常需要开发者花费额外精力去查阅文档或处理复杂的泛型。

结论

总而言之,React 19 将 ref 作为 prop 传递的改动,是一项意义重大的 “Quality of Life” 更新。它移除了一个长期以来困扰开发者的冗余模式,使 ref 的处理回归到 props 模型的统一心智模型中。这不仅让代码变得更加干净、直观,也显著降低了编写和维护可复用组件时的复杂性,是 React 团队在提升开发者体验方面迈出的坚实一步。

不知道说啥了很无语了