🧚♀️
React Hook FormでdefaultValuesが反映されない時に確認するところ
この記事について
React Hook Formを利用していると、たまにdefaultValuesが反映されないことがあります。
大抵はうまくいきますが、たまに「あれ、反映されないな?」となるので原因と解決策をまとめておきます。
開発環境
Next.jsを利用しています。
React Hook FormはV6系〜V7系までが対象です。
defaultValues
がセットされないコード
APIをリクエストした後に、data
を取得し、そのdata
をdefaultValues
にセットしています。
const { data, loading } = useNameQuery();
const {
control,
formState: { errors },
getValues,
handleSubmit,
register,
setValue,
} = useForm<any>({
mode: 'onChange',
defaultValues: {
firstName: data?.firstName,
lastName: data?.lastName
})
return (
<input {...register('firstName')} /> // undefinedになる
<input {...register('lastName')} /> // undefinedになる
)
考えられる原因
defaultValues
は一度レンダリングされた値をキャッシュします。
一度キャッシュされてしまうと、その後も動的に値は変わらないので、APIのレスポンスが取得された値をセットしたとしても値は変わりません。
defaultValues are cached on the first render within the custom hook. If you want to reset the defaultValues, you should use the reset api.
解決方法1
ドキュメントにあるように、reset
やsetValue
等を利用して動的に値を変化させるコードを書く。
const { data, loading } = useNameQuery();
const {
control,
formState: { errors },
getValues,
handleSubmit,
register,
setValue,
} = useForm<any>({
mode: 'onChange',
defaultValues: {
firstName: data?.firstName,
lastName: data?.lastName
})
useEffect(() => {
if (data) {
setValue('firstName', data?.firstName)
setValue('lastName', data?.lastName)
}
}, [setValue, data])
return (
<input {...register('firstName')} />
<input {...register('lastName')} />
)
解決方法2
V6系だと上記の方法が解決策になるかと思いますが、少し調べてみるとV7.40.0-next.0
からレスポンスの値をdefaultValues
にセットする機能(values
)が追加されたので以下の方法で解決できるようです。(まだプロジェクトで利用したことはない)
// set default value sync
function App({ values }) {
useForm({
values, // will get updated when values props updates
})
}
function App() {
const values = useFetch("/api")
useForm({
defaultValues: {
firstName: "",
lastName: "",
},
values, // will get updated once values returns
})
これは最高なアップデート!!!!!🎉🎉🎉🎉🎉
リリースノートを確認するとスタンプがたくさん付いていてみんな大喜びしていました🎊🎊
おわりに
もし他にも解決策ある場合は教えていただけるとありがたいです。
どなたかの参考になれば嬉しいです!
Discussion
かなりパワープレイですが、
という方法があると思います。(できるだけ React Hook Form の予測しづらい機能に振り回されたくないので、僕はこの方法が好きです。)
RHF の defaultValue は、useState の初期値と似た挙動を取るので、同様に考えた結果です。
このような方法があるとは初めて知りました!
教えてくださりありがとうございます!
useStateと同じような挙動だとわかりやすくて良いですね!!
この方法も開発に取り入れてみようと思います!!!💪