網站搜尋

javascript - 在使用 React.forwardRef 時,React/TypeScript 中應該給 ref 哪種類型?


我就是無法把類型寫對。我正在轉發一個 ref,如果我像下面這樣設置 ref: any,ref.current.focus() 就能正常工作。

function EditorFeat(): JSX.Element {
  const ref = useRef<HTMLElement | null>(null);

   // ...
   return (
    ......
    <Editor state={state} dispatch={dispatch} ref={ref} />
     ....
)
}

export default EditorFeat;
interface IEditor {
  state: AppState;
  dispatch: React.Dispatch<Action>;
}

// change ref:any to correct typings!
function Editor({ state, dispatch }: IEditor, ref: any): JSX.Element {
// ...
  return <DraftJsEditor ref={ref} /> // import from 'draft-js'
}

export default React.forwardRef(Editor);

但是每當我試圖正確使用 ref 類型時,我總是遇到錯誤!

如果我寫 function Editor({state, dispatch}: IEditor, ref: HTMLElement): JSX.Element

我收到以下錯誤:

  Overload 1 of 2, '(props: Readonly<DraftEditorProps>): DraftEditor', gave the following error.
    Type 'HTMLElement' is not assignable to type 'string | ((instance: DraftEditor | null) => void) | RefObject<DraftEditor> | null | undefined'.
      Type 'HTMLElement' is not assignable to type 'string'.
  Overload 2 of 2, '(props: DraftEditorProps, context?: any): DraftEditor', gave the following error.
    Type 'HTMLElement' is not assignable to type 'string | ((instance: DraftEditor | null) => void) | RefObject<DraftEditor> | null | undefined'.
      Type 'HTMLElement' is not assignable to type 'string'

如果我嘗試 React.RefObject<DraftEditor> 我會得到:

Argument of type '({ state, dispatch }: IEditor, ref: RefObject<DraftEditor>) => Element' is not assignable to parameter of type 'ForwardRefRenderFunction<DraftEditor, IEditor>'.
  Types of parameters 'ref' and 'ref' are incompatible.
    Type '((instance: DraftEditor | null) => void) | MutableRefObject<DraftEditor | null> | null' is not assignable to type 'RefObject<DraftEditor>'.
      Type 'null' is not assignable to type 'RefObject<DraftEditor>'

答案#1

使用函數型元件時,這運作得非常順利,儘管有點不尋常:

function RichEditor(props: RichEditorProps) {
  const [editor, setEditor] = React.useState<Editor | null>(null);

  React.useEffect(() => {
    editor?.focus() // or anywhere you want to use it
  }, [editor])
    

  return (
    <Editor
      ref={editor => setEditor(editor)}
    />
  )
}

答案#2

如果你直接在組件的最上方撰寫 React.forwardRef 而不是在 return 語句的行中,你只需要輸入 React.forwardRef:

interface IEditor {
  state: AppState;
  dispatch: React.Dispatch<Action>;
}

const Editor = React.forwardRef<HTMLInputElement, IEditor>({ state, dispatch }, ref) {
  // ...
  return <DraftJsEditor ref={ref} /> // import from 'draft-js'
}

export default Editor;

說明:你使用兩個泛型類型參數 T 和 P 來輸入 React.forwardRef:

React.forwardRef<T, P>(Editor)
  • T 是你最終透過 DraftJsEditor 參考的 HTML 元素的類型,所以這可能是 HTMLDivElement、HTMLInputElement 或任何其他元素。當你一開始隨便選一個錯誤的類型時,TypeScript 的錯誤訊息通常會引導你找到正確的類型。
  • P 是 Editor 組件的屬性。

所以在你的情況下,它可能是 React.forwardRef<HTMLInputElement, IEditor>(Editor),如你在上方的大解決方案中所見。