⚛️ 揭秘 React 的类型:Ref 类型

2025-06-09

⚛️ 揭秘 React 的类型:Ref 类型

在 ReactJS 中使用 TypeScript 时,在函数式组件中使用 ref 需要格外小心,以确保类型安全。本文将探讨基于 TypeScript 的函数式组件中最常用、最相关的 ref 类型。

1️⃣React.RefObject

类型React.RefObject是函数式组件中处理引用的最常用方式。当你使用钩子创建引用useRef并想要访问其当前值时,会用到它。引用容器为只读容器,其current属性无法被修改。

下面是一个使用示例React.RefObject



import { useRef } from 'react';

export const MyComponent = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleClick = () => {
    inputRef.current?.focus();
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};


Enter fullscreen mode Exit fullscreen mode

inputRef在这个例子中,我们使用钩子创建了一个名为的 ref useRef,并将类型指定为HTMLInputElement

请注意,在使用 时useRef,如果初始传递的值是null,TypeScript 会自动将其理解为React.RefObject。如果您希望它是React.MutableRefObject并且初始值也是null,那么简单的技巧就是将其定义为:



const inputRef = useRef<HTMLInputElement | null>(null);


Enter fullscreen mode Exit fullscreen mode

2️⃣React.MutableRefObject

React.MutableRefObject类型与 类似React.RefObject,但它允许current引用的属性可变。这在需要直接更新引用值而不触发重新渲染的场景中非常有用。

下面是一个使用示例React.MutableRefObject



import { useRef } from 'react';

export const MyComponent = () => {
  const counterRef = useRef<number>(0);

  const handleClick = () => {
    counterRef.current++;
    console.log('Counter value:', counterRef.current++);
  };

  return (
    <div>
      <button onClick={handleClick}>Increment Counter</button>
    </div>
  );
};


Enter fullscreen mode Exit fullscreen mode

3️⃣React.RefCallback

React.RefCallback当你需要在特定时间点访问 DOM 元素或 React 组件时(例如组件挂载或卸载时),会用到该类型。当你使用需要直接访问 DOM 的第三方库,或者需要执行复杂的 DOM 操作,或者需要管理refs 列表时,这会特别有用。其类型定义如下:



type RefCallback<T> = (instance:  T  |  null) =>  void;


Enter fullscreen mode Exit fullscreen mode

下面是一个用于React.RefCallback测量元素大小并相应更新组件状态的示例。这在需要实现响应式布局或动态 UI 元素的场景中非常有用。



import { useState, useCallback } from 'react';

export const MyComponent = () => {
  const [elementSize, setElementSize] = useState<{ width: number; height: number }>({
    width: 0,
    height: 0,
  });

  const handleElementRef: React.RefCallback<HTMLDivElement> = useCallback((element) => {
    if (!element) return;

    const { offsetWidth, offsetHeight } = element;

    setElementSize({ width: offsetWidth, height: offsetHeight });
  }, []);

  return (
    <div ref={handleElementRef}>
      <p>Element size: {elementSize.width} x {elementSize.height}</p>
    </div>
  );
};


Enter fullscreen mode Exit fullscreen mode

4️⃣React.Ref

React.Ref本质上是 React refs 所有可能形状的联合类型。你可以理解为:



type  Ref<T> = RefCallBack<T> |  RefObject<T> |  null;


Enter fullscreen mode Exit fullscreen mode

5️⃣React.ForwardedRef

当你需要将 ref 从父组件转发到子组件时,会用到该React.ForwardedRef类型。当你使用可复用组件并需要访问底层 DOM 元素或 React 组件时,或者在子组件中使用 ref 创建自定义 ref 对象时,这尤其有用useImperativeHandle

下面是一个使用示例React.ForwardedRef



import { forwardRef, Ref } from 'react';

interface InputProps {
  value: string;
  onChange: (value: string) => void;
}

const InputBase = ({ value, onChange }: InputProps, ref: React.ForwardedRef<HTMLInputElement>) => {
  return (
    <input
      type="text"
      value={value}
      onChange={(e) => onChange(e.target.value)}
      ref={ref}
    />
  );
});

export const Input = forwardRef(InputBase);


Enter fullscreen mode Exit fullscreen mode

在这个例子中,我们使用forwardRef函数创建一个 ref-forwarding 组件,它允许父组件访问底层input元素。

6️⃣React.LegacyRef

React.LegacyRef当你需要以兼容旧版 React 的方式使用 ref 时,可以使用此类型。此类型主要用于基于类的组件,这类组件在现代 React 开发中并不常见。

值得注意的是,refReact 中每个原始 HTML 元素的属性目前都具有 类型React.LegacyRef<HTMLElementType>。这意味着,如果你正在使用一个div元素,那么该属性的类型ref很可能是React.LegacyRef<HTMLDivElement>

实际上,您在 React 项目中根本不必关心这种类型。

🏁 结论

在本文中,我们探讨了 React 中最常用的 ref 类型,包括React.RefObjectReact.MutableRefObjectReact.RefCallbackReact.RefReact.ForwardedRefReact.LegacyRef。了解这些类型后,您将能够更自信地使用 TypeScript 编写 React 项目。敬请关注更多关于 React 和 TypeScript 的文章,我们将深入探讨构建健壮且可扩展应用程序的最新功能和最佳实践。

如果您认为这是一篇好文章,那么您可能也会发现我之前的文章很有用:


如果您对使用 ReactJS 进行前端开发和 Web 开发感兴趣,请关注我并查看下面个人资料中我的文章。

鏂囩珷鏉ユ簮锛�https://dev.to/itswillt/demystifying-reacts-types-ref-types-28fj
PREV
2025 年项目的终极技术栈
NEXT
为什么你的 CSS 总是杂乱无章——理解 CSS 的复杂性