diff --git a/packages/antd/README.md b/packages/antd/README.md index 9d0db0c9991..4bb9e9100ab 100644 --- a/packages/antd/README.md +++ b/packages/antd/README.md @@ -61,6 +61,8 @@ npm install --save @uform/antd - [`connect`](#connect) - [`registerFormField`](#registerFormField) - [Interfaces](#Interfaces) + - [`IFormActions`](#IFormActions) + - [`IFormAsyncActions`](#IFormAsyncActions) - [`ButtonProps`](#ButtonProps) - [`CardProps`](#CardProps) - [`ICompatItemProps`](#ICompatItemProps) @@ -2207,6 +2209,7 @@ ReactDOM.render(, document.getElementById('root')) #### `useFormEffects` > Implement local effects by using useFormEffects. Same effect as the example of [Linkage](#Linkage) +> Note: The life cycle of the listener starts from `ON_FORM_MOUNT` **Signature** @@ -2824,197 +2827,231 @@ ReactDOM.render(, document.getElementById('root')) > The Interfaces is fully inherited from @uform/react. The specific Interfaces of @uform/antd is listed below. --- -#### IForm - -> Form instance object API created by using createForm +#### IFormActions +```typescript +interface IFormActions { + /* + * Form submission, if the callback parameter returns Promise, + * Then the entire submission process will hold and load is true. + * Wait for Promise resolve to trigger the form onFormSubmitEnd event while loading is false + */ + submit( + onSubmit?: (values: IFormState['values']) => any | Promise + ): Promise<{ + Validated: IFormValidateResult + Payload: any //onSubmit callback function return value + }> + /* + * Clear the error message, you can pass the FormPathPattern to batch or precise control of the field to be cleared. + * For example, clearErrors("*(aa,bb,cc)") + */ + clearErrors: (pattern?: FormPathPattern) => void + /* + * Get status changes, mainly used to determine which states in the current life cycle have changed in the form lifecycle hook. + * For example, hasChanged(state,'value.aa') + */ + hasChanged( + target: IFormState | IFieldState | IVirtualFieldState, + path: FormPathPattern + ): boolean + /* + * Reset form + */ + reset(options?: { + // Forced to empty + forceClear?: boolean // Forced check + validate?: boolean // Reset range for batch or precise control of the field to be reset + selector?: FormPathPattern + }): Promise + /* + * Validation form + */ + validate( + path?: FormPathPattern, + options?: { + // Is it pessimistic check, if the current field encounters the first verification error, stop the subsequent verification process + first?: boolean + } + ): Promise + /* + * Set the form status + */ + setFormState( // Operation callback + callback?: (state: IFormState) => any, // No trigger the event + silent?: boolean + ): void + /* + * Get form status + */ + getFormState( //transformer + callback?: (state: IFormState) => any + ): any + /* + * Set the field status + */ + setFieldState( // Field path + path: FormPathPattern, // Operation callback + callback?: (state: IFieldState) => void, // No trigger the event + silent?: boolean + ): void + /* + * Get the field status + */ + getFieldState( // Field path + path: FormPathPattern, // Transformer + callback?: (state: IFieldState) => any + ): any + /* + * Get the form observer tree + */ + getFormGraph(): IFormGraph + /* + * Set the form observer tree + */ + setFormGraph(graph: IFormGraph): void + /* + * Listen to the form life cycle + */ + subscribe( + callback?: ({ type, payload }: { type: string; payload: any }) => void + ): number + /* + * Cancel the listening form life cycle + */ + unsubscribe(id: number): void + /* + * Trigger form custom life cycle + */ + notify: (type: string, payload?: T) => void + /* + * Set the field value + */ + setFieldValue(path?: FormPathPattern, value?: any): void + /* + * Get the field value + */ + getFieldValue(path?: FormPathPattern): any + /* + * Set the initial value of the field + */ + setFieldInitialValue(path?: FormPathPattern, value?: any): void + /* + * Get the initial value of the field + */ + getFieldInitialValue(path?: FormPathPattern): any +} +``` +#### IFormAsyncActions ```typescript -interface IForm { -  /* -   * Form submission, if the callback parameter returns Promise, -   * Then the entire submission process will hold and load is true. -   * Wait for Promise resolve to trigger the form onFormSubmitEnd event while loading is false -   */ -   submit( -      onSubmit?: (values: IFormState['values']) => any | Promise -    ): Promise<{ -       Validated: IFormValidateResult -       Payload: any //onSubmit callback function return value -   }> -    -   /* -    * Clear the error message, you can pass the FormPathPattern to batch or precise control of the field to be cleared. -    * For example, clearErrors("*(aa,bb,cc)") -    */ -   clearErrors: (pattern?: FormPathPattern) => void -    -   /* -    * Get status changes, mainly used to determine which states in the current life cycle have changed in the form lifecycle hook. -    * For example, hasChanged(state,'value.aa') -    */ -   hasChanged(target: IFormState | IFieldState | IVirtualFieldState, path: FormPathPattern): boolean -    -   /* -    * Reset form -    */ -   reset(options?: { -     // Forced to empty -     forceClear?: boolean -     // Forced check -     validate?: boolean -     // Reset range for batch or precise control of the field to be reset -     selector?: FormPathPattern -   }): Promise -    -   /* -    * Validation form -    */ -   validate(path?: FormPathPattern, options?: { -     // Is it pessimistic check, if the current field encounters the first verification error, stop the subsequent verification process -     first?:boolean -   }): Promise -    -   /* -    * Set the form status -    */ -   setFormState( -     // Operation callback -     callback?: (state: IFormState) => any, -     // No trigger the event -     silent?: boolean -   ): void -    -   /* -    * Get form status -    */ -   getFormState( -     //transformer -     callback?: (state: IFormState) => any -   ): any -    -   /* -    * Set the field status -    */ -   setFieldState( -     // Field path -     path: FormPathPattern, -     // Operation callback -     callback?: (state: IFieldState) => void, -     // No trigger the event -     silent?: boolean -   ): void -    -   /* -    * Get the field status -    */ -   getFieldState( -     // Field path -     path: FormPathPattern, -     // Transformer -     callback?: (state: IFieldState) => any -   ): any -    -   /* -    * Registration field -    */ -   registerField(props: { -    // Node path -    path?: FormPathPattern -    // Data path -    name?: string -    // Field value -    value?: any -    // Field multi-value -    values?: any[] -    // Field initial value -    initialValue?: any -    // Field extension properties -    props?: any -    // Field check rule -    rules?: ValidatePatternRules[] -    // Field is required -    required?: boolean -    // Is the field editable? -    editable?: boolean -    // Whether the field is dirty check -    useDirty?: boolean -    // Field state calculation container, mainly used to extend the core linkage rules -    computeState?: (draft: IFieldState, prevState: IFieldState) => void -  }): IField -   -  /* -   * Register virtual fields -   */ -  registerVirtualField(props: { -    // Node path -    path?: FormPathPattern -    // Data path -    name?: string -    // Field extension properties -    props?: any -    // Whether the field is dirty check -    useDirty?: boolean -    // Field state calculation container, mainly used to extend the core linkage rules -    computeState?: (draft: IFieldState, prevState: IFieldState) => void -  }): IVirtualField -   -  /* -   * Create a field data operator, which will explain the returned API in detail later. -   */ -  createMutators(field: IField): IMutators -   -  /* -   * Get the form observer tree -   */ -  getFormGraph(): IFormGraph -   -  /* -   * Set the form observer tree -   */ -  setFormGraph(graph: IFormGraph): void -   -  /* -   * Listen to the form life cycle -   */ -  subscribe(callback?: ({ -    type, -    payload -  }: { -    type: string -    payload: any -  }) => void): number -   -  /* -   * Cancel the listening form life cycle -   */ -  unsubscribe(id: number): void -   -  /* -   * Trigger form custom life cycle -   */ -  notify: (type: string, payload?: T) => void -   -  /* -   * Set the field value -   */ -  setFieldValue(path?: FormPathPattern, value?: any): void -   -  /* -   * Get the field value -   */ -  getFieldValue(path?: FormPathPattern): any -   -  /* -   * Set the initial value of the field -   */ -  setFieldInitialValue(path?: FormPathPattern, value?: any): void -   -  /* -   * Get the initial value of the field -   */ -  getFieldInitialValue(path?: FormPathPattern): any +interface IFormAsyncActions { + /* + * Form submission, if the callback parameter returns Promise, + * Then the entire submission process will hold and load is true. + * Wait for Promise resolve to trigger the form onFormSubmitEnd event while loading is false + */ + submit( + onSubmit?: (values: IFormState['values']) => void | Promise + ): Promise + /* + * Reset form + */ + reset(options?: IFormResetOptions): Promise + /* + * Get status changes, mainly used to determine which states in the current life cycle have changed in the form lifecycle hook. + * For example, hasChanged(state,'value.aa') + */ + hasChanged(target: any, path: FormPathPattern): Promise + /* + * Clear the error message, you can pass the FormPathPattern to batch or precise control of the field to be cleared. + * For example, clearErrors("*(aa,bb,cc)") + */ + clearErrors: (pattern?: FormPathPattern) => Promise + /* + * Validation form + */ + validate( + path?: FormPathPattern, + options?: { + // Is it pessimistic check, if the current field encounters the first verification error, stop the subsequent verification process + first?: boolean + } + ): Promise + /* + * Set the form state + */ + setFormState( + // Operation callback + callback?: (state: IFormState) => any, + // No trigger the event + silent?: boolean + ): Promise + /* + * Get form state + */ + getFormState( + //transformer + callback?: (state: IFormState) => any + ): Promise + /* + * Set the field state + */ + setFieldState( + // Field path + path: FormPathPattern, + // Operation callback + callback?: (state: IFieldState) => void, + // No trigger the event + silent?: boolean + ): Promise + /* + * Get the field state + */ + getFieldState( + // Field path + path: FormPathPattern, + //transformer + callback?: (state: IFieldState) => any + ): Promise + /* + * Get the form observer tree + */ + getFormGraph(): Promise + /* + * Set the form observer tree + */ + setFormGraph(graph: IFormGraph): Promise + /* + * Listen to the form life cycle + */ + subscribe(callback?: FormHeartSubscriber): Promise + /* + * Cancel the listening form life cycle + */ + unsubscribe(id: number): Promise + /* + * Trigger form custom life cycle + */ + notify: (type: string, payload: T) => Promise + dispatch: (type: string, payload: T) => void + /* + * Set the field value + */ + setFieldValue(path?: FormPathPattern, value?: any): Promise + /* + * Get the field value + */ + getFieldValue(path?: FormPathPattern): Promise + /* + * Set the initial value of the field + */ + setFieldInitialValue(path?: FormPathPattern, value?: any): Promise + /* + * Get the initial value of the field + */ + getFieldInitialValue(path?: FormPathPattern): Promise } ``` diff --git a/packages/antd/README.zh-cn.md b/packages/antd/README.zh-cn.md index 569d57d9bb9..4a654bcd2dd 100644 --- a/packages/antd/README.zh-cn.md +++ b/packages/antd/README.zh-cn.md @@ -62,6 +62,8 @@ npm install --save @uform/antd - [`connect`](#connect) - [`registerFormField`](#registerFormField) - [Interfaces](#Interfaces) + - [`IFormActions`](#IFormActions) + - [`IFormAsyncActions`](#IFormAsyncActions) - [`ButtonProps`](#ButtonProps) - [`CardProps`](#CardProps) - [`ICompatItemProps`](#ICompatItemProps) @@ -2210,6 +2212,7 @@ ReactDOM.render(, document.getElementById('root')) #### `useFormEffects` > 使用 useFormEffects 可以实现局部effect的表单组件,效果同:[简单联动](#简单联动) +> 注意:监听的生命周期是从 `ON_FORM_MOUNT` 开始 **签名** @@ -2803,12 +2806,10 @@ ReactDOM.render(, document.getElementById('root')) --- -#### IForm - -> 通过 createForm 创建出来的 Form 实例对象 API +#### IFormActions ```typescript -interface IForm { +interface IFormActions { /* * 表单提交,如果回调参数返回Promise, * 那么整个提交流程会hold住,同时loading为true, @@ -2997,6 +2998,91 @@ interface IForm { } ``` +#### IFormAsyncActions + +```typescript +interface IFormAsyncActions { + /* + * 表单提交,如果回调参数返回Promise, + * 那么整个提交流程会hold住,同时loading为true, + * 等待Promise resolve才触发表单onFormSubmitEnd事件,同时loading为false + */ + submit( + onSubmit?: (values: IFormState['values']) => void | Promise + ): Promise + /* + * 重置表单 + */ + reset(options?: IFormResetOptions): Promise + /* + * 获取状态变化情况,主要用于在表单生命周期钩子内判断当前生命周期中有哪些状态发生了变化, + * 比如hasChanged(state,'value.aa') + */ + hasChanged(target: any, path: FormPathPattern): Promise + /* + * 清空错误消息,可以通过传FormPathPattern来批量或精确控制要清空的字段, + * 比如clearErrors("*(aa,bb,cc)") + */ + clearErrors: (pattern?: FormPathPattern) => Promise + /* + * 校验表单 + */ + validate( + path?: FormPathPattern, + options?: { + //是否悲观校验,如果当前字段遇到第一个校验错误则停止后续校验流程 + first?: boolean + } + ): Promise + /* + * 设置表单状态 + */ + setFormState( + //操作回调 + callback?: (state: IFormState) => any, + //是否不触发事件 + silent?: boolean + ): Promise + /* + * 获取表单状态 + */ + getFormState( + //transformer + callback?: (state: IFormState) => any + ): Promise + /* + * 设置字段状态 + */ + setFieldState( + //字段路径 + path: FormPathPattern, + //操作回调 + callback?: (state: IFieldState) => void, + //是否不触发事件 + silent?: boolean + ): Promise + /* + * 获取字段状态 + */ + getFieldState( + //字段路径 + path: FormPathPattern, + //transformer + callback?: (state: IFieldState) => any + ): Promise + getFormGraph(): Promise + setFormGraph(graph: IFormGraph): Promise + subscribe(callback?: FormHeartSubscriber): Promise + unsubscribe(id: number): Promise + notify: (type: string, payload: T) => Promise + dispatch: (type: string, payload: T) => void + setFieldValue(path?: FormPathPattern, value?: any): Promise + getFieldValue(path?: FormPathPattern): Promise + setFieldInitialValue(path?: FormPathPattern, value?: any): Promise + getFieldInitialValue(path?: FormPathPattern): Promise +} +``` + #### ButtonProps ```typescript diff --git a/packages/next/README.md b/packages/next/README.md index 6434f77d24a..c34c2f00a60 100644 --- a/packages/next/README.md +++ b/packages/next/README.md @@ -61,6 +61,8 @@ npm install --save @uform/next - [`connect`](#connect) - [`registerFormField`](#registerFormField) - [Interfaces](#Interfaces) + - [`IFormActions`](#IFormActions) + - [`IFormAsyncActions`](#IFormAsyncActions) - [`ButtonProps`](#ButtonProps) - [`CardProps`](#CardProps) - [`ICompatItemProps`](#ICompatItemProps) @@ -2196,6 +2198,7 @@ ReactDOM.render(, document.getElementById('root')) #### `useFormEffects` > Implement local effects by using useFormEffects. Same effect as the example of [Linkage](#Linkage) +> Note: The life cycle of the listener starts from `ON_FORM_MOUNT` **Signature** @@ -2813,197 +2816,231 @@ ReactDOM.render(, document.getElementById('root')) > The Interfaces is fully inherited from @uform/react. The specific Interfaces of @uform/next is listed below. --- -#### IForm - -> Form instance object API created by using createForm +#### IFormActions +```typescript +interface IFormActions { + /* + * Form submission, if the callback parameter returns Promise, + * Then the entire submission process will hold and load is true. + * Wait for Promise resolve to trigger the form onFormSubmitEnd event while loading is false + */ + submit( + onSubmit?: (values: IFormState['values']) => any | Promise + ): Promise<{ + Validated: IFormValidateResult + Payload: any //onSubmit callback function return value + }> + /* + * Clear the error message, you can pass the FormPathPattern to batch or precise control of the field to be cleared. + * For example, clearErrors("*(aa,bb,cc)") + */ + clearErrors: (pattern?: FormPathPattern) => void + /* + * Get status changes, mainly used to determine which states in the current life cycle have changed in the form lifecycle hook. + * For example, hasChanged(state,'value.aa') + */ + hasChanged( + target: IFormState | IFieldState | IVirtualFieldState, + path: FormPathPattern + ): boolean + /* + * Reset form + */ + reset(options?: { + // Forced to empty + forceClear?: boolean // Forced check + validate?: boolean // Reset range for batch or precise control of the field to be reset + selector?: FormPathPattern + }): Promise + /* + * Validation form + */ + validate( + path?: FormPathPattern, + options?: { + // Is it pessimistic check, if the current field encounters the first verification error, stop the subsequent verification process + first?: boolean + } + ): Promise + /* + * Set the form status + */ + setFormState( // Operation callback + callback?: (state: IFormState) => any, // No trigger the event + silent?: boolean + ): void + /* + * Get form status + */ + getFormState( //transformer + callback?: (state: IFormState) => any + ): any + /* + * Set the field status + */ + setFieldState( // Field path + path: FormPathPattern, // Operation callback + callback?: (state: IFieldState) => void, // No trigger the event + silent?: boolean + ): void + /* + * Get the field status + */ + getFieldState( // Field path + path: FormPathPattern, // Transformer + callback?: (state: IFieldState) => any + ): any + /* + * Get the form observer tree + */ + getFormGraph(): IFormGraph + /* + * Set the form observer tree + */ + setFormGraph(graph: IFormGraph): void + /* + * Listen to the form life cycle + */ + subscribe( + callback?: ({ type, payload }: { type: string; payload: any }) => void + ): number + /* + * Cancel the listening form life cycle + */ + unsubscribe(id: number): void + /* + * Trigger form custom life cycle + */ + notify: (type: string, payload?: T) => void + /* + * Set the field value + */ + setFieldValue(path?: FormPathPattern, value?: any): void + /* + * Get the field value + */ + getFieldValue(path?: FormPathPattern): any + /* + * Set the initial value of the field + */ + setFieldInitialValue(path?: FormPathPattern, value?: any): void + /* + * Get the initial value of the field + */ + getFieldInitialValue(path?: FormPathPattern): any +} +``` +#### IFormAsyncActions ```typescript -interface IForm { -  /* -   * Form submission, if the callback parameter returns Promise, -   * Then the entire submission process will hold and load is true. -   * Wait for Promise resolve to trigger the form onFormSubmitEnd event while loading is false -   */ -   submit( -      onSubmit?: (values: IFormState['values']) => any | Promise -    ): Promise<{ -       Validated: IFormValidateResult -       Payload: any //onSubmit callback function return value -   }> -    -   /* -    * Clear the error message, you can pass the FormPathPattern to batch or precise control of the field to be cleared. -    * For example, clearErrors("*(aa,bb,cc)") -    */ -   clearErrors: (pattern?: FormPathPattern) => void -    -   /* -    * Get status changes, mainly used to determine which states in the current life cycle have changed in the form lifecycle hook. -    * For example, hasChanged(state,'value.aa') -    */ -   hasChanged(target: IFormState | IFieldState | IVirtualFieldState, path: FormPathPattern): boolean -    -   /* -    * Reset form -    */ -   reset(options?: { -     // Forced to empty -     forceClear?: boolean -     // Forced check -     validate?: boolean -     // Reset range for batch or precise control of the field to be reset -     selector?: FormPathPattern -   }): Promise -    -   /* -    * Validation form -    */ -   validate(path?: FormPathPattern, options?: { -     // Is it pessimistic check, if the current field encounters the first verification error, stop the subsequent verification process -     first?:boolean -   }): Promise -    -   /* -    * Set the form status -    */ -   setFormState( -     // Operation callback -     callback?: (state: IFormState) => any, -     // No trigger the event -     silent?: boolean -   ): void -    -   /* -    * Get form status -    */ -   getFormState( -     //transformer -     callback?: (state: IFormState) => any -   ): any -    -   /* -    * Set the field status -    */ -   setFieldState( -     // Field path -     path: FormPathPattern, -     // Operation callback -     callback?: (state: IFieldState) => void, -     // No trigger the event -     silent?: boolean -   ): void -    -   /* -    * Get the field status -    */ -   getFieldState( -     // Field path -     path: FormPathPattern, -     // Transformer -     callback?: (state: IFieldState) => any -   ): any -    -   /* -    * Registration field -    */ -   registerField(props: { -    // Node path -    path?: FormPathPattern -    // Data path -    name?: string -    // Field value -    value?: any -    // Field multi-value -    values?: any[] -    // Field initial value -    initialValue?: any -    // Field extension properties -    props?: any -    // Field check rule -    rules?: ValidatePatternRules[] -    // Field is required -    required?: boolean -    // Is the field editable? -    editable?: boolean -    // Whether the field is dirty check -    useDirty?: boolean -    // Field state calculation container, mainly used to extend the core linkage rules -    computeState?: (draft: IFieldState, prevState: IFieldState) => void -  }): IField -   -  /* -   * Register virtual fields -   */ -  registerVirtualField(props: { -    // Node path -    path?: FormPathPattern -    // Data path -    name?: string -    // Field extension properties -    props?: any -    // Whether the field is dirty check -    useDirty?: boolean -    // Field state calculation container, mainly used to extend the core linkage rules -    computeState?: (draft: IFieldState, prevState: IFieldState) => void -  }): IVirtualField -   -  /* -   * Create a field data operator, which will explain the returned API in detail later. -   */ -  createMutators(field: IField): IMutators -   -  /* -   * Get the form observer tree -   */ -  getFormGraph(): IFormGraph -   -  /* -   * Set the form observer tree -   */ -  setFormGraph(graph: IFormGraph): void -   -  /* -   * Listen to the form life cycle -   */ -  subscribe(callback?: ({ -    type, -    payload -  }: { -    type: string -    payload: any -  }) => void): number -   -  /* -   * Cancel the listening form life cycle -   */ -  unsubscribe(id: number): void -   -  /* -   * Trigger form custom life cycle -   */ -  notify: (type: string, payload?: T) => void -   -  /* -   * Set the field value -   */ -  setFieldValue(path?: FormPathPattern, value?: any): void -   -  /* -   * Get the field value -   */ -  getFieldValue(path?: FormPathPattern): any -   -  /* -   * Set the initial value of the field -   */ -  setFieldInitialValue(path?: FormPathPattern, value?: any): void -   -  /* -   * Get the initial value of the field -   */ -  getFieldInitialValue(path?: FormPathPattern): any +interface IFormAsyncActions { + /* + * Form submission, if the callback parameter returns Promise, + * Then the entire submission process will hold and load is true. + * Wait for Promise resolve to trigger the form onFormSubmitEnd event while loading is false + */ + submit( + onSubmit?: (values: IFormState['values']) => void | Promise + ): Promise + /* + * Reset form + */ + reset(options?: IFormResetOptions): Promise + /* + * Get status changes, mainly used to determine which states in the current life cycle have changed in the form lifecycle hook. + * For example, hasChanged(state,'value.aa') + */ + hasChanged(target: any, path: FormPathPattern): Promise + /* + * Clear the error message, you can pass the FormPathPattern to batch or precise control of the field to be cleared. + * For example, clearErrors("*(aa,bb,cc)") + */ + clearErrors: (pattern?: FormPathPattern) => Promise + /* + * Validation form + */ + validate( + path?: FormPathPattern, + options?: { + // Is it pessimistic check, if the current field encounters the first verification error, stop the subsequent verification process + first?: boolean + } + ): Promise + /* + * Set the form state + */ + setFormState( + // Operation callback + callback?: (state: IFormState) => any, + // No trigger the event + silent?: boolean + ): Promise + /* + * Get form state + */ + getFormState( + //transformer + callback?: (state: IFormState) => any + ): Promise + /* + * Set the field state + */ + setFieldState( + // Field path + path: FormPathPattern, + // Operation callback + callback?: (state: IFieldState) => void, + // No trigger the event + silent?: boolean + ): Promise + /* + * Get the field state + */ + getFieldState( + // Field path + path: FormPathPattern, + //transformer + callback?: (state: IFieldState) => any + ): Promise + /* + * Get the form observer tree + */ + getFormGraph(): Promise + /* + * Set the form observer tree + */ + setFormGraph(graph: IFormGraph): Promise + /* + * Listen to the form life cycle + */ + subscribe(callback?: FormHeartSubscriber): Promise + /* + * Cancel the listening form life cycle + */ + unsubscribe(id: number): Promise + /* + * Trigger form custom life cycle + */ + notify: (type: string, payload: T) => Promise + dispatch: (type: string, payload: T) => void + /* + * Set the field value + */ + setFieldValue(path?: FormPathPattern, value?: any): Promise + /* + * Get the field value + */ + getFieldValue(path?: FormPathPattern): Promise + /* + * Set the initial value of the field + */ + setFieldInitialValue(path?: FormPathPattern, value?: any): Promise + /* + * Get the initial value of the field + */ + getFieldInitialValue(path?: FormPathPattern): Promise } ``` diff --git a/packages/next/README.zh-cn.md b/packages/next/README.zh-cn.md index 67728040f9d..491a904fb59 100644 --- a/packages/next/README.zh-cn.md +++ b/packages/next/README.zh-cn.md @@ -62,6 +62,8 @@ npm install --save @uform/next - [`connect`](#connect) - [`registerFormField`](#registerFormField) - [Interfaces](#Interfaces) + - [`IFormActions`](#IFormActions) + - [`IFormAsyncActions`](#IFormAsyncActions) - [`ButtonProps`](#ButtonProps) - [`CardProps`](#CardProps) - [`ICompatItemProps`](#ICompatItemProps) @@ -2208,6 +2210,7 @@ ReactDOM.render(, document.getElementById('root')) #### `useFormEffects` > 使用 useFormEffects 可以实现局部effect的表单组件,效果同:[简单联动](#简单联动) +> 注意:监听的生命周期是从 `ON_FORM_MOUNT` 开始 **签名** @@ -2805,8 +2808,11 @@ ReactDOM.render(, document.getElementById('root')) > 通过 createForm 创建出来的 Form 实例对象 API + +#### IFormActions + ```typescript -interface IForm { +interface IFormActions { /* * 表单提交,如果回调参数返回Promise, * 那么整个提交流程会hold住,同时loading为true, @@ -2897,55 +2903,6 @@ interface IForm { callback?: (state: IFieldState) => any ): any - /* - * 注册字段 - */ - registerField(props: { - //节点路径 - path?: FormPathPattern - //数据路径 - name?: string - //字段值 - value?: any - //字段多参值 - values?: any[] - //字段初始值 - initialValue?: any - //字段扩展属性 - props?: any - //字段校验规则 - rules?: ValidatePatternRules[] - //字段是否必填 - required?: boolean - //字段是否可编辑 - editable?: boolean - //字段是否走脏检查 - useDirty?: boolean - //字段状态计算容器,主要用于扩展核心联动规则 - computeState?: (draft: IFieldState, prevState: IFieldState) => void - }): IField - - /* - * 注册虚拟字段 - */ - registerVirtualField(props: { - //节点路径 - path?: FormPathPattern - //数据路径 - name?: string - //字段扩展属性 - props?: any - //字段是否走脏检查 - useDirty?: boolean - //字段状态计算容器,主要用于扩展核心联动规则 - computeState?: (draft: IFieldState, prevState: IFieldState) => void - }): IVirtualField - - /* - * 创建字段数据操作器,后面会详细解释返回的API - */ - createMutators(field: IField): IMutators - /* * 获取表单观察者树 */ @@ -2995,6 +2952,91 @@ interface IForm { } ``` +#### IFormAsyncActions + +```typescript +interface IFormAsyncActions { + /* + * 表单提交,如果回调参数返回Promise, + * 那么整个提交流程会hold住,同时loading为true, + * 等待Promise resolve才触发表单onFormSubmitEnd事件,同时loading为false + */ + submit( + onSubmit?: (values: IFormState['values']) => void | Promise + ): Promise + /* + * 重置表单 + */ + reset(options?: IFormResetOptions): Promise + /* + * 获取状态变化情况,主要用于在表单生命周期钩子内判断当前生命周期中有哪些状态发生了变化, + * 比如hasChanged(state,'value.aa') + */ + hasChanged(target: any, path: FormPathPattern): Promise + /* + * 清空错误消息,可以通过传FormPathPattern来批量或精确控制要清空的字段, + * 比如clearErrors("*(aa,bb,cc)") + */ + clearErrors: (pattern?: FormPathPattern) => Promise + /* + * 校验表单 + */ + validate( + path?: FormPathPattern, + options?: { + //是否悲观校验,如果当前字段遇到第一个校验错误则停止后续校验流程 + first?: boolean + } + ): Promise + /* + * 设置表单状态 + */ + setFormState( + //操作回调 + callback?: (state: IFormState) => any, + //是否不触发事件 + silent?: boolean + ): Promise + /* + * 获取表单状态 + */ + getFormState( + //transformer + callback?: (state: IFormState) => any + ): Promise + /* + * 设置字段状态 + */ + setFieldState( + //字段路径 + path: FormPathPattern, + //操作回调 + callback?: (state: IFieldState) => void, + //是否不触发事件 + silent?: boolean + ): Promise + /* + * 获取字段状态 + */ + getFieldState( + //字段路径 + path: FormPathPattern, + //transformer + callback?: (state: IFieldState) => any + ): Promise + getFormGraph(): Promise + setFormGraph(graph: IFormGraph): Promise + subscribe(callback?: FormHeartSubscriber): Promise + unsubscribe(id: number): Promise + notify: (type: string, payload: T) => Promise + dispatch: (type: string, payload: T) => void + setFieldValue(path?: FormPathPattern, value?: any): Promise + getFieldValue(path?: FormPathPattern): Promise + setFieldInitialValue(path?: FormPathPattern, value?: any): Promise + getFieldInitialValue(path?: FormPathPattern): Promise +} +``` + #### ButtonProps ```typescript diff --git a/packages/react/README.md b/packages/react/README.md index 5e2329e4b38..980b9d643e4 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -1946,6 +1946,7 @@ interface IFormConsumerProps { #### `useFormEffects` > Implement local effects by using useFormEffects. Same effect as the example of [Linkage](#Linkage) +> Note: The life cycle of the listener starts from `ON_FORM_MOUNT` **Signature** @@ -2828,38 +2829,6 @@ interface IFormActions { path: FormPathPattern, // Transformer callback?: (state: IFieldState) => any ): any - /* - * Registration field - */ - registerField(props: { - // Node path - path?: FormPathPattern // Data path - name?: string // Field value - value?: any // Field multi-value - values?: any[] // Field initial value - initialValue?: any // Field extension properties - props?: any // Field check rule - rules?: ValidatePatternRules[] // Field is required - required?: boolean // Is the field editable? - editable?: boolean // Whether the field is dirty check - useDirty?: boolean // Field state calculation container, mainly used to extend the core linkage rules - computeState?: (draft: IFieldState, prevState: IFieldState) => void - }): IField - /* - * Register virtual fields - */ - registerVirtualField(props: { - // Node path - path?: FormPathPattern // Data path - name?: string // Field extension properties - props?: any // Whether the field is dirty check - useDirty?: boolean // Field state calculation container, mainly used to extend the core linkage rules - computeState?: (draft: IFieldState, prevState: IFieldState) => void - }): IVirtualField - /* - * Create a field data operator, which will explain the returned API in detail later. - */ - createMutators(field: IField): IMutators /* * Get the form observer tree */ diff --git a/packages/react/README.zh-cn.md b/packages/react/README.zh-cn.md index 7484ab00c1f..cad77d2a734 100644 --- a/packages/react/README.zh-cn.md +++ b/packages/react/README.zh-cn.md @@ -1986,6 +1986,7 @@ interface IFormConsumerProps { #### `useFormEffects` > 使用 useFormEffects 可以实现局部effect的表单组件,效果同:[简单联动](#简单联动) +> 注意:监听的生命周期是从 `ON_FORM_MOUNT` 开始 **签名** @@ -2855,55 +2856,6 @@ interface IFormActions { callback?: (state: IFieldState) => any ): any - /* - * 注册字段 - */ - registerField(props: { - //节点路径 - path?: FormPathPattern - //数据路径 - name?: string - //字段值 - value?: any - //字段多参值 - values?: any[] - //字段初始值 - initialValue?: any - //字段扩展属性 - props?: any - //字段校验规则 - rules?: ValidatePatternRules[] - //字段是否必填 - required?: boolean - //字段是否可编辑 - editable?: boolean - //字段是否走脏检查 - useDirty?: boolean - //字段状态计算容器,主要用于扩展核心联动规则 - computeState?: (draft: IFieldState, prevState: IFieldState) => void - }): IField - - /* - * 注册虚拟字段 - */ - registerVirtualField(props: { - //节点路径 - path?: FormPathPattern - //数据路径 - name?: string - //字段扩展属性 - props?: any - //字段是否走脏检查 - useDirty?: boolean - //字段状态计算容器,主要用于扩展核心联动规则 - computeState?: (draft: IFieldState, prevState: IFieldState) => void - }): IVirtualField - - /* - * 创建字段数据操作器,后面会详细解释返回的API - */ - createMutators(field: IField): IMutators - /* * 获取表单观察者树 */ diff --git a/packages/react/src/__tests__/useFieldState.spec.tsx b/packages/react/src/__tests__/useFieldState.spec.tsx new file mode 100644 index 00000000000..3aa5977a9fa --- /dev/null +++ b/packages/react/src/__tests__/useFieldState.spec.tsx @@ -0,0 +1,76 @@ +import React from 'react' +import { act, renderHook } from '@testing-library/react-hooks' +import { Form, useFieldState, Field, VirtualField } from '..' + + +describe('useFieldState hook', () => { + test('Field useFieldState', async () => { + + const FieldWrapper = (props) => { + const { children } = props + return
+ + {() => children} + +
+ } + + const Fragment = () => { + const [fieldState, setLocalFieldState ] = useFieldState({ ext: 0 }) + const { ext } = fieldState as any + + return { + ext: ext, + setExt: (val) => { + (setLocalFieldState as ((nextState?: any) => void))({ ext: val }) + } + } + } + + const { result, rerender } = renderHook(Fragment, { + wrapper: FieldWrapper + }) + + expect(result.current.ext).toEqual(0) + act(() => { + result.current.setExt(2) + }) + rerender() + expect(result.current.ext).toEqual(2) + }) + + test('virtualField useFieldState', async () => { + + const FieldWrapper = (props) => { + const { children } = props + return
+ + {() => children} + +
+ } + + const Fragment = () => { + const [fieldState, setLocalFieldState ] = useFieldState({ ext: 0 }) + const { ext } = fieldState as any + + return { + ext: ext, + setExt: (val) => { + (setLocalFieldState as ((nextState?: any) => void))({ ext: val }) + } + } + } + + const { result, rerender } = renderHook(Fragment, { + wrapper: FieldWrapper + }) + + expect(result.current.ext).toEqual(0) + act(() => { + result.current.setExt(2) + }) + rerender() + expect(result.current.ext).toEqual(2) + }) +}) diff --git a/packages/react/src/__tests__/useFormEffects.spec.tsx b/packages/react/src/__tests__/useFormEffects.spec.tsx new file mode 100644 index 00000000000..72f2f924049 --- /dev/null +++ b/packages/react/src/__tests__/useFormEffects.spec.tsx @@ -0,0 +1,145 @@ +import React from 'react' +import { act, renderHook } from '@testing-library/react-hooks' +import { useFormEffects, Form, LifeCycleTypes, Field, createFormActions } from '..' + +const InputField = props => ( + + {({ state, mutators }) => { + const loading = state.props.loading + return + {props.label && } + {loading ? ' loading... ' : } + {state.errors} + {state.warnings} + + }} + +) + +describe('useFormEffects hook', () => { + test('useFormEffects', async () => { + const formInitFn = jest.fn() + const effectInitFn = jest.fn() + const formMountFn = jest.fn() + const effectMountFn = jest.fn() + + let effectMountState + let mountState + + const Fragment = () => { + useFormEffects(($, actions) => { + $(LifeCycleTypes.ON_FORM_INIT).subscribe(() => { + effectInitFn(LifeCycleTypes.ON_FORM_INIT) + }) + $(LifeCycleTypes.ON_FORM_MOUNT).subscribe((state) => { + effectMountState = state + effectMountFn(LifeCycleTypes.ON_FORM_MOUNT, state) + }) + }) + return
+ } + + const FormWrapper = (props) => { + return
{ + $(LifeCycleTypes.ON_FORM_INIT).subscribe(() => { + formInitFn(LifeCycleTypes.ON_FORM_INIT) + }) + + $(LifeCycleTypes.ON_FORM_MOUNT).subscribe((state) => { + mountState = state + formMountFn(LifeCycleTypes.ON_FORM_MOUNT, state) + }) + }}> + + {props.children} + + } + + renderHook(Fragment, { + wrapper: FormWrapper + }) + + expect(formInitFn).toBeCalledWith(LifeCycleTypes.ON_FORM_INIT) + expect(formInitFn).toBeCalledTimes(1) + + expect(effectInitFn).toBeCalledTimes(0) + + expect(formMountFn).toBeCalledWith(LifeCycleTypes.ON_FORM_MOUNT, mountState) + expect(formMountFn).toBeCalledTimes(1) + + expect(effectMountFn).toBeCalledWith(LifeCycleTypes.ON_FORM_MOUNT, effectMountState) + expect(effectMountFn).toBeCalledTimes(1) + + expect(effectMountState).toEqual(mountState) + expect(effectMountState.mounted).toEqual(true) + }) + + test('unmount test', async () => { + const actions = createFormActions() + const effectFieldChangeFn = jest.fn() + const formFieldChangeFn = jest.fn() + + let effectFieldChangeState + let formFieldChangeState + + const Fragment = () => { + useFormEffects(($, actions) => { + $(LifeCycleTypes.ON_FIELD_VALUE_CHANGE).subscribe((state) => { + effectFieldChangeFn(LifeCycleTypes.ON_FIELD_VALUE_CHANGE) + effectFieldChangeState = state + }) + }) + return
+ } + + const FormWrapper = (props) => { + return
{ + $(LifeCycleTypes.ON_FIELD_VALUE_CHANGE).subscribe((state) => { + formFieldChangeFn(LifeCycleTypes.ON_FIELD_VALUE_CHANGE) + formFieldChangeState = state + }) + }}> + + {props.children} + + } + + const { unmount, rerender } = renderHook(Fragment, { + wrapper: FormWrapper + }) + + expect(effectFieldChangeFn).toBeCalledTimes(0) + expect(formFieldChangeFn).toBeCalledTimes(0) + + expect(formFieldChangeState).toEqual(undefined) + expect(effectFieldChangeState).toEqual(undefined) + + act(() => { + actions.setFieldValue('a', 1) + }) + + expect(effectFieldChangeFn).toBeCalledTimes(1) + expect(formFieldChangeFn).toBeCalledTimes(1) + + expect(formFieldChangeState).toEqual(effectFieldChangeState) + + unmount() + // unmount will trigger unscribe event, ignore any changes + act(() => { + actions.setFieldValue('a', 2) + }) + + rerender() + expect(effectFieldChangeFn).toBeCalledTimes(1) + expect(formFieldChangeFn).toBeCalledTimes(1) + + expect(formFieldChangeState.value).toEqual(1) + expect(effectFieldChangeState.value).toEqual(1) + }) +}) diff --git a/packages/react/src/__tests__/useFormState.spec.tsx b/packages/react/src/__tests__/useFormState.spec.tsx new file mode 100644 index 00000000000..3e317008c16 --- /dev/null +++ b/packages/react/src/__tests__/useFormState.spec.tsx @@ -0,0 +1,31 @@ +import { act, renderHook } from '@testing-library/react-hooks' +import { Form, useFormState } from '..' + + +describe('useFormState hook', () => { + test('useFormState', async () => { + + const Fragment = () => { + const [formState, setFormState ] = useFormState({ ext: 0 }) + const { ext } = formState as any + + return { + ext: ext, + setExt: (val) => { + (setFormState as ((nextState?: any) => void))({ ext: val }) + } + } + } + + const { result, rerender } = renderHook(Fragment, { + wrapper: Form + }) + + expect(result.current.ext).toEqual(0) + act(() => { + result.current.setExt(2) + }) + rerender() + expect(result.current.ext).toEqual(2) + }) +}) diff --git a/packages/react/src/hooks/useFormEffects.ts b/packages/react/src/hooks/useFormEffects.ts index 878e5ccc494..773bbc0c37f 100644 --- a/packages/react/src/hooks/useFormEffects.ts +++ b/packages/react/src/hooks/useFormEffects.ts @@ -21,4 +21,4 @@ export function useFormEffects(effects: IFormEffect) { form.unsubscribe(subscribeId) } }, []) -} +} \ No newline at end of file