useFormState
useFormState
是用来创建表单状态管理器对象的自定义 React Hook。通过表单状态管理器对象,我们可以管理与表单相关的状态,包括:
- 表单值
- 表单校验状态
- 表单提交状态
引用:
import { useFormState } from '@sinoui/rx-form-state';
使用方式
注意:因为useFormState
是 React Hook,所以必须在 React 函数组件中使用。
import { useFormState } from '@sinoui/rx-form-state';function FormDemo() {const initialValue = {}; // 表单默认值const options = {}; // 创建表单状态管理器的配置const formState = useFormState(initialValue, options);}
通过useFormState()
产生的formState
往往会与FormStateContext结合在一起使用,将formState
通过 React 上下文的方式共享到子组件:
import React from 'react';import { useFormState, FormStateContext, Field } from '@sinoui/rx-form-state';function FormDemo() {const initialValue = {}; // 表单默认值const options = {}; // 创建表单状态管理器的配置const formState = useFormState(initialValue, options);return (<FormStateContext.Provider value={formState}><form><label>姓名:<Field as="input" name="userName" required /></label><label>年龄:<Field as="input" name="age" required /></label></form></FormStateContext.Provider>);}
看一下演示效果:
方法参数
useFormState
方法声明如下:
useFormState<T>(initialValues: T = {}, options?: FormStateOptions<T>): FormState;
方法的第一个参数initialValues
是初始的表单值,可以不指定,默认为{}
。方法的第二个参数options
是表单状态管理器的配置,有如下配置选项:
配置项 | 类型 | 描述 |
---|---|---|
validate | `(value:any,values: T) => FormStateErrors | undefined` |
onSubmit | `(values: T, formState: FormState) => Promise<any> | void` |
relys | RelyRule<T>[] | 指定表单域值关联逻辑。 |
enableReinitialize | boolean | 是否监听initialValues 值变更,如果发生变更,则重新应用新的表单初始值。默认为true ,表示启用。 |
relys
是用来指定表单域值关联计算的规则,例如:
const relys = [// 规则1:A = B + C['B','C',(draft) => {draft.A = draft.B + draft.C;},],// 规则2:E = D['D',(draft) => {draft.E = draft.D;},],// 规则3:F = A * E['A','E',(draft) => {draft.F = draft.A * draft.E;},],];
也可以通过 addRelyRule
动态添加值关联规则,如下所示:
const formState = useFormState();useEffect(() => {const remove = formState.addRelyRule(['B', 'C'], (draft) => {draft.A = draft.B + draft.C;});return remove; // 返回移除校验规则的函数}, [formState]);
表单状态管理器对象formState
useFormState()
返回formState
表单状态管理器对象。通过formState
,可以获取和更新表单状态。
获取表单状态
formState
有以下属性可用来获取不同的表单状态:
属性名 | 类型 | 描述 |
---|---|---|
values | T | 表单值。 |
errors | FormStateErrors | 表单同步验证错误状态。 |
isTouched | FormStateTouched | 表单域被操作状态。 |
asyncErrors | FormStateErrors | 表单异步校验错误状态。 |
isPending | FormStatePending | 执行异步校验的过程状态。 |
isSubmitting | boolean | 表单提交中状态。 |
isFormPending | boolean | 表单是否有进行中的异步校验。 |
isValid | boolean | 表单验证是否通过。 |
通过这些属性即可获取到表单值、校验错误等状态。
如果你的组件关注表单状态的变更,也就是说当成组件状态使用,那么需要用到下面提供的获取表单状态的 React Hooks:
hook | 类型 | 描述 |
---|---|---|
useFormSubmitting | (formState?: FormState) => void | 获取表单提交中状态的 hook。在表单提交时特别有用。 |
useFormSelect | <T, M>(formState: FormState<T>, selector: (FormStateModel: FormStateModel<T>) => M): M 或者 <T, M>(selector: (FormStateModel: FormStateModel<T>) => M): M | 提取表单状态的 hook。 |
下面通过两个例子来看一看如何使用这两个 hooks。
例子 1:在表单中使用的提交按钮
在表单中使用的提交按钮,我们定义为SubmitButton
组件。在组件内部可以获取到formState
上下文,所以无需将formState
传递给上面介绍的两个 hook。如下所示:
function SubmitButton() {const isSubmitting = useFormSubmitting();const submitEnabled = useFormSelect((formStateModel) =>!formStateModel.isFormPending &&formStateModel.isValid &&!formStateModel.isSubmitting,);return (<button type="submit" disabled={!submitEnabled}>{isSubmitting ? '正在提交表单...' : '提交'}</button>);}
使用方式类似如:
const formState = useFormState();<Form formState={formState}><SubmitButton /></Form>;
例子 2:在表单外部使用的提交按钮
在表单外部使用提交按钮,那么这个按钮无法从上下文中获取到formState
,则需要通过属性传递给SubmitButton
。代码如下:
function SubmitButton({ formState }: { formState: FormState }) {const isSubmitting = useFormSubmitting(formState);const submitEnabled = useFormSelect(formState,(formStateModel) =>!formStateModel.isFormPending &&formStateModel.isValid &&!formStateModel.isSubmitting,);return (<button type="submit" disabled={!submitEnabled} onClick={formState.submit}>{isSubmitting ? '正在提交表单...' : '提交'}</button>);}
使用方式类似如:
const formState = useFormState();<div><Form formState={formState}></Form><SubmitButton formState={formState} /></div>;
获取表单域状态
formState
提供了两个方法,用来直接获取表单域状态的:
方法 | 类型 | 描述 |
---|---|---|
getFieldState | (fieldName: string): FieldStateModel | 获取一个表单域状态的方法。 |
获取到的状态有:
interface FieldStateModel {/*** 表单域名称*/name: string;/*** 表单域值*/value: any;/*** 表单错误*/error?: string | null;/*** 表单异步错误*/asyncError?: string | null;/*** 被操作状态*/isTouched: boolean;/*** 异步校验过程状态*/isPending: boolean;}
我们还可以通过以下自定义 hook,在组件内获取表单域状态:
- useFieldState - 获取单个表单域的状态
- useFieldValue - 获取单个表单域的值
- useFieldError - 获取表单域的验证错误
- useFieldTouhed - 获取表单域是否被点击过的状态
更新表单状态
formState
提供了一些方法,用来更新表单状态:
方法 | 类型 | 描述 |
---|---|---|
updateState | (producer: (draft: FormStateModel<T>) => void): FormStateModel<T> | 更新表单状态。 |
setValues | (values: T) => void | 更新表单值。 |
setInitialValues | (initialValues: T) => void | 更新表单初始值。 |
validate | () => boolean | 验证表单。返回验证结果。如果有校验错误,则返回false ,否则返回true 。 |
setErrors | (errors: FormStateErrors) => void | 设置表单校验错误 |
setTouched | (touched: FormStateTouched) => void | 设置所有表单域的点击状态 |
setAsyncErrors | (asyncErrors: FormStateErrors) => void | 设置异步校验错误 |
setPending | (isPending: FormStatePending): void | 设置表单异步校验的过程状态 |
reset | (defaultValues?: T): void | 重置表单 |
submit | (event?: React.FormEvent<HTMLFormElement>): Promise<any> | 提交表单 |
setSubmitting | (submiting: boolean): void | 设置提交中状态 |
特别说明一下updateState()
方法。此方法可以设置表单状态的任何地方,采用的是immer的方法更新表单状态,例如:
formState.updateState((draft) => {draft.values.A = '1';draft.touched.A = true;draft.errors.A = '必须大于2';});
更新表单域状态
formState
提供了一些直接操作表单域状态的方法:
方法 | 类型 | 描述 |
---|---|---|
setFieldState | (fieldName: string, producer: (draft: FieldStateModel) => void): FieldStateModel | 设置表单域状态 |
setFieldValue | (fieldName: string, value: any): void | 设置表单域的值。 |
validateField | (fieldName: string): void | 校验表单域 |
validateFields | (...fieldNames: string[]): Promise<boolean> | 同时验证多个表单域 |
setFieldTouched | (fieldName: string, isTouched?: boolean): void | 设置表单域的被操作状态 |
setFieldError | (fieldName: string, error?: string): void | 设置表单域错误 |
setFieldPending | (fieldName: string, isPending: boolean): void | 设置表单域的异步校验过程状态 |
setFieldAsyncError | (fieldName: string, asyncError?: string): void | 设置表单域的异步错误 |
blur | (fieldName: string): void | 处理表单域失去焦点事件 |
除了这些方法,还可以使用useField来获取一些更新表单域的方法。
表单域配置
通过表单域配置,可以为表单域指定校验、异步校验、值关联规则。formState
提供了更新表单域配置的方法:
方法 | 类型 | 描述 |
---|---|---|
addField | (field: FieldConfig): void | 添加表单域配置 |
removeField | (fieldName: string): void | 删除表单域配置 |
表单域配置类型FielConfig
如下:
export interface FieldConfig {/*** 表单域名称*/name: string;/*** 表单域校验方法** @param {*} value 表单域值* @param {*} values 表单值* @returns {(string | undefined | null)}*/validate(value: any, values: any): string | undefined | null;/*** 表单域异步校验方法** @param {*} value 表单域值* @param {*} values 表单值** @returns {(string | undefined | null | Promise<string | undefined>} 返回校验结果*/asyncValidate?: (value: any,values: any,) => Promise<string | undefined> | undefined;/*** 关联字段名*/relyFields?: string[];/*** 值关联计算方法*/relyFn?: (values: any) => any;}