😇

Reactで親から子のメソッドをuseRefを使わずに呼ぶ

2022/07/10に公開

モチベーション

モチベーションとしては

  • 「React 親から子 メソッド」とかで検索してもuseRefを使うやり方しか出てこない
  • useRefを用いてしまうとコードが手続的になってしまう
  • そもそも親から子のメソッドを呼ぶというのはuseRefを使うほどのことなんだろうか?
    と思ったのでちょっとVueの時にやったやり方を思い出して、やってみた感じです。

「こっちが絶対正しい!」というよりは「こういうやり方もあるんじゃない?」くらいの感じなので、ご意見あればコメントください!

背景

CreditCardForm.tsxという形でクレカフォームを共通化した。
内部的にStripeのReactライブラリを使っている。

Parent.tsx
<Elements stripe={stripePromise}>
  <CreditCardForm />
</Elements>

しくみとしては

  1. CreditCardForm.tsxにクレカ情報が入力される
  2. Stripeライブラリがクレカ情報をAPIにPOSTし、トークンを返してくれる。(createPaymentMethod)
    そしてそのAPI(createPaymentMethod)はElementsの子コンポーネント内でしか呼べない。

色々あって、要件的にこのAPIを親コンポーネントから呼びたくなった。(割愛)

親から子のメソッドをuseRefを使わずに呼ぶ

  1. 親にフラグを追加し、子に渡す
Parent.tsx
  const [handleFlg, setHandleFlg] = useState(false)

...

<Elements stripe={stripePromise}>
  <CreditCardForm handleFlg={handleFlg} />
</Elements>
  1. 子に渡しuseEffectで検知させる。
CreditCardForm.tsx
  const handleCardRegister = useCallback(async () => {
    // 詳しくは省略〜
    await stripe.createPaymentMethod()
  }, [...])

  useEffect(() => {
    if (!handleFlg) return

    handleCardRegister()
  }, [handleCardRegister, handleFlg])
  1. 子のメソッドを呼びたいタイミングでフラグをtrueに
Parent.tsx
  const [handleFlg, setHandleFlg] = useState(false)
  const handleSubmit = () => {
    setHandleFlg(true)
  }

おわり!

良い点

  • useRefやらuseImperativeHandleやらのあまり使わないようなAPIを使わない

悪い点

  • useEffectを使う
  • useEffectもフラグも使うのでピタゴラスイッチ感がすごい

最後に

まぁここまで書いてみてあれですが、素直にuseRef使った方が良かったのかな、、と思ったりしました。
以前Vueで親からのpropsをwatchして子でメソッドを呼ぶみたいなのをやった記憶があって、もちろんVueでもピタゴラスイッチ感が否めなかったのでどうしようもない時以外はやらないんですが、そのReact版です。
手続的になるのが嫌な人はこっちのやり方もあるよーくらいの記事でした。

Discussion