Chakra UI 搭配 React-Hook-Form,文件上沒說清楚的地方

查閱 Chakra UI 和 React Hook Form 的文件,已經能夠滿足 8 成的使用情況,但是,在建立表單元件 <Radio /><Checkbox />,就沒那麼順利了,在文件上找不到如何搭配使用。

使用環境

"next": ^13.1.1,
"@chakra-ui/react": ^2.4.6,
"react-hook-form": ^7.41.5

Chakra UI 的標誌

Chakra UI

React Hook Form 的標誌

React Hook Form


接下來的內容


一般用法

使用 <Input /> 的表單,只要按照 React Hook Form 的說明,加上 register() 即可:

import { useForm } from 'react-hook-form';
import { Input } from '@chakra-ui/react';

const { register } = useForm({ defaultValues });

<Input {...register('name', { required: true })} />

文件上說明得很清楚,就不再贅述。


Radio 和 Checkbox 的用法

Chakra UI 的 RadioCheckbox 通常不是如 html 表單直接使用,而是有語法規則:

import { RadioGroup, Radio, CheckboxGroup, Checkbox, Stack } from '@chakra-ui/react';

<RadioGroup>
  <Stack>
    <Radio>選項一</Radio>
    <Radio>選項二</Radio>
    <Radio>選項三</Radio>
  </Stack>
</RadioGroup>

<CheckboxGroup>
  <Stack>
    <Checkbox>選項一</Checkbox>
    <Checkbox>選項二</Checkbox>
    <Checkbox>選項三</Checkbox>
  </Stack>
</CheckboxGroup>

試過很多方法,卻總是在與 defaultValues 相關的情境不如預期。

// ❌ 會出現錯誤的語法

// 在 Group 層級加上 register()

<RadioGroup {...register('range')}>
  <Stack>
    ...
  </Stack>
</RadioGroup>

<CheckboxGroup {...register('option')}>
  <Stack>
    ...
  </Stack>
</CheckboxGroup>

// 或在選項加上 register()

<RadioGroup>
  <Stack>
    <Radio {...register('range')} value={0}>
      選項一
    </Radio>
    <Radio {...register('range')} value={1}>
      選項二
    </Radio>
    <Radio {...register('range')} value={2}>
      選項三
    </Radio>
  </Stack>
</RadioGroup>

<CheckboxGroup>
  <Stack>
    <Checkbox {...register('option')} value={0}>
      選項一
    </Checkbox>
    <Checkbox {...register('option')} value={1}>
      選項二
    </Checkbox>
    <Checkbox {...register('option')} value={2}>
      選項三
    </Checkbox>
  </Stack>
</CheckboxGroup>

正確的方法是使用 React Hook Form 的 Controller

// ✅ 正確的語法

import { useForm, Controller } from 'react-hook-form';
import { RadioGroup, Radio, CheckboxGroup, Checkbox, Stack } from '@chakra-ui/react';

const { control } = useForm({ defaultValues });

<Controller
  name="range" //改用 name
  control={control}
  render={({ field }) => (
    <RadioGroup {...field}>
      <Stack>
        <Radio value={0}>選項一</Radio>
        <Radio value={1}>選項二</Radio>
        <Radio value={2}>選項三</Radio>
      </Stack>
    </RadioGroup>
  )}
/>

<Controller
  name="option" //改用 name
  control={control}
  render={({ field }) => (
    <RadioGroup {...field}>
      <Stack>
        <Radio value={0}>選項一</Radio>
        <Radio value={1}>選項二</Radio>
        <Radio value={2}>選項三</Radio>
      </Stack>
    </RadioGroup>
  )}
/>

可能會沒注意到的地方

React Hook Form 儲存資料的格式一律是字串。

所以在使用 <Radio /><Checkbox /> 的時候,若把 value 值指定為數字,並設定 defaultValue

// ⚠️ 選項一應要預設選取
import { useForm, Controller } from 'react-hook-form';
import { RadioGroup, Radio, Stack } from '@chakra-ui/react';

const { control } = useForm({ defaultValues });

<Controller
  name="range"
  control={control}
  render={({ field }) => (
    <RadioGroup {...field} defaultValue={0}>
      <Stack>
        <Radio value={0}>選項一</Radio>
        <Radio value={1}>選項二</Radio>
        <Radio value={2}>選項三</Radio>
      </Stack>
    </RadioGroup>
  )}
/>

會發現無法讓 value0選項一預設選取。

需把是數字的 defaultValue 轉為字串:

// ✅ 正確的語法(之一)

defaultValue={`${0}`}