今天來說說如何將 React Hook Form 與其他 UI 框架結合使用~
昨天的範例是使用原生的表單標籤,但實際開發上,還是會傾向使用 UI 框架提供的表單元件,那如何當個兩個都要的成熟大人呢?要知道這個問題的答案,首先我們先知道什麼是受控元件和非受控元件:
function UncontrolledExample() {
return (
<form>
{/* React 沒有 value state,input 自己管理 */}
<input type="text" defaultValue="預設值" />
</form>
)
}
import { useState } from "react"
function ControlledExample() {
const [value, setValue] = useState("")
return (
<form>
<input
type="text"
value={value} // 受 React state 控制
onChange={(e) => setValue(e.target.value)}
/>
<p>目前輸入:{value}</p>
</form>
)
}
所以我們必須先了解我們使用的 UI 框架的元件是屬於受控還是非受控元件,若是非受控元件,我們就能直接在該元件上直接使用 register 綁定:
//範例使用的是 shadcn 的 Input元件
<Input
placeholder="帳號"
{...register("username", { required: "必填欄位" })}
/>
若為受控元件就必須出動 React Hook Form 的 Controller!!
//範例使用的是 MUI 的 TextField 元件
import { useForm, Controller } from "react-hook-form"
import TextField from "@mui/material/TextField"
import Button from "@mui/material/Button"
export default function DemoForm() {
// 初始化 useForm
const { control, handleSubmit } = useForm({
defaultValues: { username: "" }
})
// 提交表單
const onSubmit = (data: FormData) => {
console.log("表單資料:", data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* Controller 將 RHF 與受控元件 TextField 連結 */}
<Controller
name="username" //欄位名稱,必要屬性
control={control} //從 useForm 解構出來的 control 對象,必要屬性,提供欄位管理功能。
rules={{ required: "必填欄位" }} //驗證規則 (Validation Rules),等同 register 的
rules
render={({ field, fieldState }) => ( //callback,必要屬性,接收 { field,
fieldState, formState },回傳 JSX 元件,在這裡帶入受控元件。
<TextField
label="帳號"
value={field.value}
onChange={field.onChange}
error={!!fieldState.error}
helperText={fieldState.error?.message}
/>
)}
/>
<Button type="submit" variant="contained">
送出
</Button>
</form>
)
}
雖然 Controller 主要是為了應對受控元件,但我更傾向把它理解成 UI 元件與 React Hook Form 的媒介~
今天先這樣了,明天再接續說說表單驗證!