やりたいこと
下画面のようにラジオボタンの選択によってテキストフォームを出し分けたい
前提知識
- Reactの基本知識
- typescriptの基本知識
- chakra-uiの基本知識
- react-hook-formの基本知識
発生した問題
export function Form() {
const { register, watch } = useForm();
const [value, setValue] = useState("male");
const watchText = watch("age", "");
const elem = (
<Box>
<FormLabel>年齢</FormLabel>
<Input
{...register("age", {
required: {
value: true,
message: "入力必須",
},
})}
></Input>
</Box>
);
return (
<Box margin="20px">
<FormControl>
<RadioGroup value={value} onChange={setValue}>
<Box>
<HStack>
<Radio value="male">男性</Radio>
<Fade in={value === "male"}>{elem}</Fade>
</HStack>
</Box>
<Box>
<HStack>
<Radio value="female">女性</Radio>
<Fade in={value === "female"}>{elem}</Fade>
</HStack>
</Box>
<Box>
<HStack>
<Radio value="other">その他</Radio>
<Fade in={value === "other"}>{elem}</Fade>
</HStack>
</Box>
</RadioGroup>
<Button colorScheme={"teal"}>送信</Button>
</FormControl>
</Box>
);
}
elemでテキストフォームを定義し、ラジオボタンの選択によってelemを出現させようとしています。
しかしこれでは「男性」もしくは「女性」が選択されている場合 テキストフォームが入力不可になってしまいます。
そしてなぜか「その他」を選択された状態だと入力できます。この原因が分からずかなり苦戦してしまいました。
原因
コンポーネント内で使われていませんが
const watchText = watch("age", "");
このwatchTextのせいで入力不可となっていました。
watch()はreact-hook-formのメソッドで、registerによって登録したフィールド名(ここでは"age")を参照し
その入力内容を保持します。
しかし今回同じフィールド名で登録されているInput要素が3か所出現してしまっています。
これではwatchTextがどのInput要素を参照すればよいか分かりません。
これを制御するために「その他」のテキストフォームのみ入力可になっていたんだと思われます。
解決法
registerのフィールド名とInput要素は1対1にしなければなりません。
(Fadeタグのおかげで1対1になっていると思っていました)
<RadioGroup value={value} onChange={setValue}>
<Box>
<HStack>
<Radio value="male">男性</Radio>
<Fade in={value === "male"}>{value === "male" && elem}</Fade>
</HStack>
</Box>
<Box>
<HStack>
<Radio value="female">女性</Radio>
<Fade in={value === "female"}>{value === "female" && elem}</Fade>
</HStack>
</Box>
<Box>
<HStack>
<Radio value="other">その他</Radio>
<Fade in={value === "other"}>{value === "other" && elem}</Fade>
</HStack>
</Box>
</RadioGroup>
このようにすることで例えば「男性」が選択された場合、各Fadeタグ内の要素は順に elem, false, false となるためInput要素を1つにすることができます。
さいごに
単純な問題を難しく考えてしまっていましたが、同じような問題が発生した方の参考になればうれしいです!