⚛️

【React+TypeScript】親から子コンポーネントのメソッドを叩く

2023/03/04に公開

React+TypeScriptな環境で親から子コンポーネントのメソッドを叩く時に型まわりでハマったのでまとめます。
子コンポーネント側はforwardRefを使う。
親コンポーネント側はrefを参照したい子コンポーネントに設定する。

https://beta.reactjs.org/reference/react/forwardRef

useImperativeHandleで子コンポーネントのメソッドを親に公開できる。
こんな感じ。 (useImperativeHandle使ったとき、refをhtml側に設定しなくていいことに気付くのにハマった... 設定してるとTypeScriptでエラー吐く。)

import { forwardRef, useImperativeHandle, ComponentPropsWithoutRef } from 'react'

// ComponentPropsWithoutRefはpropsに明示的にrefを含めないためにやってるのでなくてもOK
type Props = ComponentPropsWithoutRef<'div'> & {
  // propsで渡すものがある時はここに定義
}

// 親に公開したいメソッドを定義
export type ChildRefMethods = {
  start: () => void
}

export const Child = forwardRef<ChildRefMethods, Props>(function Child({ ...props }, ref) {
  const start = () => {
    console.log('start')
  }

  useImperativeHandle(
    ref,
    () => {
      return {
        start,
      }
    },
    []
  )

  return (
    <div {...props}>
      <p>Child</p>
    </div>
  )
})

親側ではこんな感じで使う。

import { FC, useRef } from 'react'
import { Child, ChildRefMethods } from '...' // 定義した参照先

type Props = {}

export const Parent: FC<Props> = () => {
  const childRef = useRef<ChildRefMethods>(null)

  function onDebugChild() {
    childRef.current?.start() // startを叩ける
  }

  return (
    <>
      <button onClick={onDebugChild}>Child参照テスト</button>
      <Child ref={childRef} />
    </>
  )
}

ComponentPropsWithoutRefについてはこちらの記事へのコメントが参考になりました🙏

https://zenn.dev/takepepe/articles/atoms-type-definitions#comment-61d59e51c9db36

確認環境
React: 18.2.0
TypeScript: 4.9.5

Discussion