React Hook Form
で、二つのフォームを連動させたい!
ついでに、その値も表示したいなぁ~~
とりあえず枠組みを用意
React
でフォームを用意したい場合、React Hook Form
がいいみたい。
<input>
と useState()
をいい感じに管理してくれる。
これを使って、二つのフォームを連動させてみる。
'use client'
import { useForm } from 'react-hook-form'
export default function MyApp() {
const form = useForm({
defaultValues: {
name: '初期値',
},
})
const nameValue = form.watch('name')
return (
<form>
<div className="p-4 flex flex-col gap-2">
<div>
今の値:
{nameValue}
</div>
<input
className="input"
{...form.register('name')}
/>
<input
className="input"
{...form.register('name')}
/>
</div>
</form>
)
}
フォームに React Hook Form
を紐づけるには register()
メソッドを付与する。
このメソッドは、以下の4つの要素を <input>
に付与する。
また、フォームの値を使用したい場合は watch()
メソッドを使用する。
これを使わないと再レンダリングが動かないので注意。
でもこのやり方だと、後のフォームしかうまく動かない。
おそらく二つの EventListener か Observer が競合しているのだろう。
フォームA → フォームB の順番で処理されてしまって、React 側とフォーム側の連動が壊れてしまっている。
試行錯誤の末
'use client'
import { useForm } from 'react-hook-form'
export default function MyApp() {
const form = useForm({
defaultValues: {
name: '初期値',
},
})
const nameValue = form.watch('name')
return (
<form>
<div className="p-4 flex flex-col gap-2">
<div>
今の値:
{nameValue}
</div>
<input
className="input"
{...form.register('name', {
onChange: (e) => {
form.setValue('name', e.target.value)
},
})}
/>
<input
className="input"
{...form.register('name', {
onChange: (e) => {
form.setValue('name', e.target.value)
},
})}
/>
</div>
</form>
)
}
register()
の引数で onChange()
として、フォームの値を再度記録しているのがポイント。
そうすることで、値を再度強制的に同期して解決!
(これが最適解かはわからない。。。)
おわりに
onChange()
はコードを読むとバリデーションとか色々なことをやっているみたい。
これってバグなのかな...仕様なのかな...。
ちょっと全コードは追いきれなかった...。
こういう体験をすると Vue
がこの辺の処理をいかに隠匿しているかがわかる。
それがいいか悪いかはべつとしt