【套件】React-Hook-Form
簡介
React Hook Form,用於管理表單輸入,並使用React的Hooks 。它可以讓你更容易地管理表單輸入,同時簡化了驗證和錯誤處理的過程。
React Hook Form有很多優點,其中一個是它的性能。它可以在大型表單中快速處理數據,並且在渲染組件時不會產生額外的性能負擔。此外,它還有很多可定制的選項,可以根據你的需求進行調整。
React Hook Form 有以下重要的 Methods :
- useForm hook: 用於註冊表單,創建一個表單實例。在這裡你可以定義表單的配置選項,例如驗證規則,表單默認值等。
- useFormContext hook: 用於訪問全局表單上下文,可以在表單實例的所有子組件中使用。
- register: 用於註冊表單控件,例如輸入框、下拉列表等。它可以將輸入控件的值與表單實例關聯起來。
- handleSubmit: 用於處理表單提交事件,並在提交之前驗證表單輸入的數據。
- errors: 包含表單輸入驗證錯誤的對象。如果輸入框中的值無效,則將在這裡添加相應的錯誤信息。
- watch: 用於監聽表單控件的值,當值改變時,它可以觸發一些副作用。
- setValue: 用於對監聽的對象直接設定輸入
- resetField: 用於對監聽的對象清除當前輸入內容
- reset: 用於對監聽的所有對象清除當前輸入內容
- clearErrors: 用於清除 Errors 提示
- formState 為object, 可取出 { errors, isSubmitting } 兩種值
- useForm 除了可以插入 resolver 改變語系以外, 也能改變 onSubmit 模式 mode: 'onChange' | 'onBlur' | 'onSubmit' | 'onTouched' | 'all',
簡單案例
下面是一個簡單的例子,如何使用React Hook Form創建一個表單:
import React from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
type Inputs = {
firstName: string;
lastName: string;
};
export default function MyForm() {
const {
register,
handleSubmit,
watch,
formState: { errors }
} = useForm<Inputs>();
const onSubmit: SubmitHandler<Inputs> = (data) => {
console.log(data);
};
console.log(watch('firstName'));
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input type='text' {...register('firstName', { required: true })} />
{errors.firstName && <span>This field is required</span>}
<input type='text' {...register('lastName', { required: true })} />
{errors.lastName && <span>This field is required</span>}
<button type='submit'>Submit</button>
</form>
);
}
在這個例子中,我們使用了useForm hook來創建一個表單實例。我們還使用了register方法來註冊輸入框,並使用required屬性來設置輸入框的必填性。如果輸入框中沒有值,則會在errors對象中添加相應的錯誤信息。 最後,我們使用handleSubmit方法來處理表單提交事件,並將表單數據作為參數傳遞給onSubmit回調函數。
配合多國語言(以yup為例)
初始化 i18n 設定
// /plugins/formI18n.ts
import i18n from 'i18next';
import { useTranslation, initReactI18next } from 'react-i18next';
i18n
.use(initReactI18next)
.init({
resources: {
hans: {
translation: {
"不可空白": "请输入至少一个简体",
}
},
hant: {
translation: {
"不可空白": "請至少輸入一個繁體",
}
}
},
lng: 'hans',
fallbackLng: 'hans',
interpolation: {
escapeValue: false
}
});
export function FormI18n () {
const { changeLanguage, language } = i18n;
const { t } = useTranslation();
const changTest = language === 'hans' ? 'hant' : 'hans';
const toggleLanguage = () => changeLanguage(changTest)
return {t, toggleLanguage, language}
}
接著將 yup 引入組件, 並設定指定表格的 schema
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import { FormI18n } from '../../plugins/formI18n';
import * as yup from 'yup';
interface IFormInputs {
firstName: string;
age: number;
}
export default function App() {
const { t, toggleLanguage, language } = FormI18n();
const schemaI18n = yup.object({
firstName: yup.string().required(`${t('不可空白')}`)
});
// ...
}
最後在 useForm({ resolver }) 添加 yupResolver 將剛設定好的 schema 注入
// .....
export default function App() {
// .....
const {
register,
handleSubmit,
setValue,
resetField,
reset,
clearErrors,
formState: { errors, isSubmitting }
} = useForm<IFormInputs>({
resolver: yupResolver(schemaI18n)
})
const onSubmit = (data: IFormInputs) => {
console.log(data);
};
// .....
}
範例附上其他常用 Methods 如下方按鈕備註
// .....
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('firstName')} />
<p>{errors.firstName?.message}</p>
<input {...register('age')} />
<p>{errors.age?.message}</p>
<button disabled={isSubmitting} type='submit'>
{isSubmitting ? 'Submitting...' : 'Submit'}
</button>
</form>
<div style={{ margin: '1rem' }}>
<button style={{ margin: '0 1rem' }} onClick={() => setValue('firstName', '點選填入字串')}>
點選填入字串
</button>
<button onClick={() => resetField('firstName')}>清除指定input</button>
</div>
<div style={{ margin: '1rem' }}>
<button style={{ margin: '0 1rem' }} onClick={() => reset()}>
清除所有input
</button>
<button onClick={toggleLanguage}>更換語言 {language}</button>
</div>
<div style={{ margin: '1rem' }}>
<button style={{ margin: '0 1rem' }} onClick={() => clearErrors()}>
清除錯誤
</button>
</div>
</>
);
完整範例程式碼
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import { FormI18n } from '../../plugins/formI18n';
import * as yup from 'yup';
interface IFormInputs {
firstName: string;
age: number;
}
export default function App() {
const { t, toggleLanguage, language } = FormI18n();
const schemaI18n = yup.object({
firstName: yup.string().required(`${t('不可空白')}`)
});
const {
register,
handleSubmit,
setValue,
resetField,
reset,
clearErrors,
formState: { errors, isSubmitting }
} = useForm<IFormInputs>({
resolver: yupResolver(schemaI18n)
});
const onSubmit = (data: IFormInputs) => {
console.log(data);
};
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('firstName')} />
<p>{errors.firstName?.message}</p>
<input {...register('age')} />
<p>{errors.age?.message}</p>
<button disabled={isSubmitting} type='submit'>
{isSubmitting ? 'Submitting...' : 'Submit'}
</button>
</form>
<div style={{ margin: '1rem' }}>
<button style={{ margin: '0 1rem' }} onClick={() => setValue('firstName', '點選填入字串')}>
點選填入字串
</button>
<button onClick={() => resetField('firstName')}>清除指定input</button>
</div>
<div style={{ margin: '1rem' }}>
<button style={{ margin: '0 1rem' }} onClick={() => reset()}>
清除所有input
</button>
<button onClick={toggleLanguage}>更換語言 {language}</button>
</div>
<div style={{ margin: '1rem' }}>
<button style={{ margin: '0 1rem' }} onClick={() => clearErrors()}>
清除錯誤
</button>
</div>
</>
);
}