😇
Reactで親から子のメソッドをuseRefを使わずに呼ぶ
モチベーション
モチベーションとしては
- 「React 親から子 メソッド」とかで検索してもuseRefを使うやり方しか出てこない
- useRefを用いてしまうとコードが手続的になってしまう
- そもそも親から子のメソッドを呼ぶというのはuseRefを使うほどのことなんだろうか?
と思ったのでちょっとVueの時にやったやり方を思い出して、やってみた感じです。
「こっちが絶対正しい!」というよりは「こういうやり方もあるんじゃない?」くらいの感じなので、ご意見あればコメントください!
背景
CreditCardForm.tsxという形でクレカフォームを共通化した。
内部的にStripeのReactライブラリを使っている。
Parent.tsx
<Elements stripe={stripePromise}>
<CreditCardForm />
</Elements>
しくみとしては
- CreditCardForm.tsxにクレカ情報が入力される
- Stripeライブラリがクレカ情報をAPIにPOSTし、トークンを返してくれる。(createPaymentMethod)
そしてそのAPI(createPaymentMethod)はElements
の子コンポーネント内でしか呼べない。
色々あって、要件的にこのAPIを親コンポーネントから呼びたくなった。(割愛)
親から子のメソッドをuseRefを使わずに呼ぶ
- 親にフラグを追加し、子に渡す
Parent.tsx
const [handleFlg, setHandleFlg] = useState(false)
...
<Elements stripe={stripePromise}>
<CreditCardForm handleFlg={handleFlg} />
</Elements>
- 子に渡しuseEffectで検知させる。
CreditCardForm.tsx
const handleCardRegister = useCallback(async () => {
// 詳しくは省略〜
await stripe.createPaymentMethod()
}, [...])
useEffect(() => {
if (!handleFlg) return
handleCardRegister()
}, [handleCardRegister, handleFlg])
- 子のメソッドを呼びたいタイミングでフラグをtrueに
Parent.tsx
const [handleFlg, setHandleFlg] = useState(false)
const handleSubmit = () => {
setHandleFlg(true)
}
おわり!
良い点
- useRefやらuseImperativeHandleやらのあまり使わないようなAPIを使わない
悪い点
- useEffectを使う
- useEffectもフラグも使うのでピタゴラスイッチ感がすごい
最後に
まぁここまで書いてみてあれですが、素直にuseRef使った方が良かったのかな、、と思ったりしました。
以前Vueで親からのpropsをwatchして子でメソッドを呼ぶみたいなのをやった記憶があって、もちろんVueでもピタゴラスイッチ感が否めなかったのでどうしようもない時以外はやらないんですが、そのReact版です。
手続的になるのが嫌な人はこっちのやり方もあるよーくらいの記事でした。
Discussion