ref 为 null Typescript + NextJS

ref is null Typescript + NextJS

我需要从父组件中的自定义子组件调用方法。

但不幸的是,对子组件(称为 CanvasUI)的引用始终为空。我不明白为什么在我看来我已经正确实施了所有内容。

这是我的父组件

...

export default function Home() {
  ...
  const canvas = useRef<CanvasRef>(null);

  ...
  function clearCanvas() {
    // canvas.current.resetCanvas();
    console.log(canvas.current);
  }
  return (
    <div className="flex justify-center items-center min-h-screen min-w-screen bg-main">
      <div className="flex flex-col">
        ...
        <div className="flex justify-center">
          ...
          <CanvasUI disabled={disableCanvas} word={activeWord} ref={canvas} />
          ...
        </div>
        ...
        <button onClick={() => clearCanvas()}>clear canvas</button>
      </div>
    </div>
  );
}

这是 CanvasUI 组件

...

export default function CanvasUI({
  disabled,
  word,
  ref,
}: {
  disabled: boolean;
  word: string;
  ref: Ref<CanvasRef>;
}) {
  ...
  useImperativeHandle(ref, () => ({ getCanvas, loadCanvas, resetCanvas }));

  ...

  function resetCanvas(): void {
    ...
  }

  ...

  function getCanvas(): String {
    ...
  }

  function loadCanvas(data: String, immediate: Boolean): void {
    ...
  }

  return (
    ...
  );
}

CanvasRef 界面

export default interface CanvasRef {
  getCanvas: () => String;
  loadCanvas: (data: String, immediate: Boolean) => void;
  resetCanvas: () => void;
}

我省略了不重要的代码以使其更具可读性

您不能在组件中使用 ref 作为 prop,因为它是 reserved(就像 key)。当调用你的函数组件时,React 将省略 props 中的 ref 属性。

相反,您应该将 ref 定位为 CanvasUI 组件的第二个参数,然后使用 forwardRef. This is explained in the documentation for useImperativeHandle:

创建它

useImperativeHandle

useImperativeHandle(ref, createHandle, [deps])

useImperativeHandle customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases. useImperativeHandle should be used with forwardRef:

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

In this example, a parent component that renders <FancyInput ref={inputRef} /> would be able to call inputRef.current.focus().