Skip to main content

如何在 react-hook-form 使用 UI 庫元件

前言

react-hook-form 的範例中,大多以 native input 直接使用 register 函數,來讓套件擁有 input 的掌控權,進一步有了表單驗證的功能

const { onChange, onBlur, name, ref } = register('firstName');
// include type check against field path with the name you have supplied.

<input
onChange={onChange} // assign onChange event
onBlur={onBlur} // assign onBlur event
name={name} // assign name prop
ref={ref} // assign ref prop
/>
// same as above
<input {...register('firstName')} />

不過,如果使用 Chakra UI 或是 MUI 這些 UI 元件庫,元件都包得像是俄羅斯娃娃,直接使用 register 通常沒辦法讓套件「深入控制」

尤其要驗證 date picker 或是 slider 這類元件的 value,就更需要出動 Controller 功能了

這次會以 MUI 作為範例

預備知識

Controller 基本 props 架構

control : 從 const { handleSubmit, control } = useForm() 而來,並傳入 Controller 當中,讓套件擁有擁有掌握權來驗證 value

name : 該 input 的 unique name,如果要讓其他 input 取得另一個 input 的值來驗證時,特別好用 (檢查密碼與確認密碼是否相符)

rules : 驗證規則,從基本的非空值到 Regex,甚至是 custom function 都可以,先詳見 官方文件

defaultValue : input 預設值,不得為 undefined

<form onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control} // 讓 react-hook-form 取得掌控
name={name} // 此 input 的 unique name
rules={{ required: "不得為空" }} // 驗證規則
defaultValue="" // value 預設值 不得為undefined
// render props: 如何render
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
variant="standard"
label="使用者名稱"
error={!!error}
helperText={error && error.message}
/>
)}
/>
<Button variant="contained" type="submit">
送出
</Button>
</form>

Controller render

Controller 的 render 會傳入套件設定好的 prop 來渲染要用的元件,以下介紹比較重要的部分

  • field
    • input value 的 state 跟 set State 都會由 react-hook-form 幫你做
    • value : 此 input 的 value state
    • onChange : 套件更新此 input value 的 state handler
  • fieldState
    • 記錄這個 input 的狀態,例如是否驗證成功、是否有被觸控點擊
  • formState
<Controller
control={control}
name="test"
render={({
field: { onChange, onBlur, value, name, ref },
fieldState: { invalid, isTouched, isDirty, error },
formState,
}) => (
// your component
)}
/>

有時候不是什麼資訊都會全部用上,就會如上面的範例,可以只取需要的部份運用

render={({ field, fieldState: { error } }) => (
<TextField
{...field}
variant="standard"
label="使用者名稱"
error={!!error}
helperText={error && error.message}
/>
)}

範例 demo