forwardRef

43 阅读1分钟
import React, { useRef } from 'react';

// 1. 子组件:使用 forwardRef 包裹
const FancyInput = React.forwardRef((props, ref) => {
  // 将父组件传来的 ref 绑定到内部的 input 元素上
  return <input ref={ref} {...props} />;
});

// 2. 父组件
function ParentComponent() {
  // 创建一个 ref 对象
  const inputRef = useRef(null);

  const handleClick = () => {
    // 通过 ref 直接操作子组件内部的 input 元素
    if (inputRef.current) {
      inputRef.current.focus(); // 让输入框获得焦点
    }
  };

  return (
    <div>
      {/* 将 ref 传递给子组件 */}
      <FancyInput ref={inputRef} placeholder="点击按钮试试" />
      <button onClick={handleClick}>聚焦输入框</button>
    </div>
  );
}

export default ParentComponent;

如果你不希望直接暴露整个 DOM 节点,而是希望子组件提供一个明确的“操作手册”,可以结合 useImperativeHandleHook 来实现更精确的控制。

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);
  
  // 使用 useImperativeHandle 自定义暴露给父组件的实例值
  useImperativeHandle(ref, () => ({
    // 只暴露一个 focus 方法
    focus: () => {
      inputRef.current.focus();
    },
    // 甚至可以暴露一个自定义方法
    sayHello: () => {
      alert('Hello from the input!');
    }
  }));

  return <input ref={inputRef} {...props} />;
});

// 父组件用法不变,但现在只能调用 .current.focus() 或 .current.sayHello()