diff --git a/CHANGELOG.md b/CHANGELOG.md index e0ab30755..607b315ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # 更新日志 +## 3.2.1 + +- 修复 `Form` 在页面渲染完成后 调用中 setFieldsValue 无效问题 [#1408](https://github.com/XiaoMi/hiui/issues/1408) + ## 3.2.0 - 新增 HiUI 基础样式 css 文件 [#1338](https://github.com/XiaoMi/hiui/issues/1338) diff --git a/components/cascader/Cascader.js b/components/cascader/Cascader.js index 8a36eb9e3..71af10b7e 100644 --- a/components/cascader/Cascader.js +++ b/components/cascader/Cascader.js @@ -137,7 +137,7 @@ const Cascader = (props) => { } } }, - [changeOnSelect, expandTrigger] + [changeOnSelect, expandTrigger, onChange, cascaderValue, popperShow] ) const clearValue = useCallback( diff --git a/components/form/Form.js b/components/form/Form.js index 64b5a62ed..99b64c2d0 100644 --- a/components/form/Form.js +++ b/components/form/Form.js @@ -2,7 +2,7 @@ import React, { useEffect, useCallback, useReducer, forwardRef } from 'react' import _ from 'lodash' import classNames from 'classnames' import PropTypes from 'prop-types' -import FormReducer, { FILEDS_UPDATE, FILEDS_UPDATE_LIST } from './FormReducer' +import Immutable, { FILEDS_UPDATE, FILEDS_UPDATE_LIST } from './FormReducer' import FormContext from './FormContext' import { transformValues } from './utils' @@ -19,7 +19,6 @@ const getClassNames = (props) => { _className[`hi-form--readOnly`] = readOnly return _className } - const InternalForm = (props) => { const { children, @@ -30,7 +29,7 @@ const InternalForm = (props) => { onValuesChange, _type // SchemaForm 内部配置变量 } = props - const [state, dispatch] = useReducer(FormReducer, { + const [state, dispatch] = useReducer(Immutable.FormReducer, { fields: [], listNames: [], listValues: {}, @@ -41,7 +40,7 @@ const InternalForm = (props) => { // 用户手动设置表单数据 const setFieldsValue = useCallback( (values) => { - const _fields = _.cloneDeep(fields) + const _fields = Immutable.currentStateFields() _fields.forEach((item) => { const { field } = item // eslint-disable-next-line no-prototype-builtins diff --git a/components/form/FormReducer.js b/components/form/FormReducer.js index 223127b4e..2d82dfb53 100644 --- a/components/form/FormReducer.js +++ b/components/form/FormReducer.js @@ -1,3 +1,5 @@ +import _ from 'lodash' + /* eslint-disable no-case-declarations */ export const FILEDS_INIT = 'FILEDS_INIT' export const FILEDS_UPDATE = 'FILEDS_UPDATE' @@ -5,30 +7,45 @@ export const FILEDS_UPDATE_VALUE = 'FILEDS_UPDATE_VALUE' export const FILEDS_REMOVE = 'FILEDS_REMOVE' export const FILEDS_INIT_LIST = 'FILEDS_INIT_LIST' export const FILEDS_UPDATE_LIST = 'FILEDS_UPDATE_LIST' -const FormReducer = (state, action) => { - switch (action.type) { - case FILEDS_INIT: - const { fields } = state - const initfields = [...fields].filter((item) => { - return action.payload.field !== item.field - }) - return Object.assign({}, { ...state }, { fields: initfields.concat(action.payload) }) - case FILEDS_UPDATE: - return Object.assign({}, { ...state }, { fields: [...action.payload] }) - case FILEDS_REMOVE: - const _fields = state.fields.filter((item) => { - return action.payload !== item.field && action.payload !== item.propsField - }) - return Object.assign({}, { ...state }, { fields: _fields }) +class Immutable { + constructor() { + this.state = {} + } + + FormReducer = (state, action) => { + switch (action.type) { + case FILEDS_INIT: + const { fields } = state + const initfields = [...fields].filter((item) => { + return action.payload.field !== item.field + }) + this.state = Object.assign({}, { ...state }, { fields: initfields.concat(action.payload) }) + return this.state + case FILEDS_UPDATE: + return Object.assign({}, { ...state }, { fields: [...action.payload] }) + case FILEDS_REMOVE: + const _fields = state.fields.filter((item) => { + return action.payload !== item.field && action.payload !== item.propsField + }) + this.state = Object.assign({}, { ...state }, { fields: _fields }) + return this.state + case FILEDS_INIT_LIST: + const { listNames } = state + !listNames.includes(action.payload) && listNames.push(action.payload) + this.state = Object.assign({}, { ...state }, { listNames: listNames }) + + return this.state + case FILEDS_UPDATE_LIST: + this.state = Object.assign({}, { ...state }, { listValues: action.payload }) + return this.state + default: + this.state = state + return state + } + } - case FILEDS_INIT_LIST: - const { listNames } = state - !listNames.includes(action.payload) && listNames.push(action.payload) - return Object.assign({}, { ...state }, { listNames: listNames }) - case FILEDS_UPDATE_LIST: - return Object.assign({}, { ...state }, { listValues: action.payload }) - default: - return state + currentStateFields() { + return _.cloneDeep(this.state.fields) } } -export default FormReducer +export default new Immutable() diff --git a/docs/demo/form/section-check.jsx b/docs/demo/form/section-check.jsx index 1dc4afaea..957c9706b 100644 --- a/docs/demo/form/section-check.jsx +++ b/docs/demo/form/section-check.jsx @@ -34,6 +34,56 @@ const code = [ store:'' }, checkedIndex: -1, + options: [ + { + id: '手机', + content: '手机', + children: [ + { + id: '小米', + content: '小米', + children: [ + { + id: '小米3', + content: '小米3' + }, + { + id: '小米4', + content: '小米4' + }, + ] + }, + { + id: '红米', + content: '红米', + children: [ + { + id: '红米3', + content: '红米3' + }, + { + id: '红米4', + content: '红米4' + } + ] + } + ] + }, + { + id: '电视', + content: '电视', + children: [ + { + id: '小米电视4A', + content: '小米电视4A' + }, + { + id: '小米电视4C', + content: '小米电视4C' + } + ] + } + ], rules: { name: { required: true, @@ -65,7 +115,7 @@ const code = [ handleSubmit() { this.form.current.validate((valid,error) => { - console.log(valid,error) + console.log('valid:',valid,'error:',error) if(!error) { console.log(valid) alert('submit') @@ -128,11 +178,21 @@ const code = [ }} /> + + { + console.log('change') + }} + data={this.state.options} + style={{ width: '100%' }} + /> + + diff --git a/docs/zh-CN/components/form.mdx b/docs/zh-CN/components/form.mdx index e444731eb..d05528ae8 100755 --- a/docs/zh-CN/components/form.mdx +++ b/docs/zh-CN/components/form.mdx @@ -72,14 +72,14 @@ import DemoUseForm from '../../demo/form/section-useForm.jsx' ### Form -| 参数 | 说明 | 类型 | 可选值 | 默认值 | -| -------------- | ------------------------------------------------------------------------------------- | ------- | -------------------------- | ---------- | -| initialValues | 表单默认值,只有初始化以及重置时生效 | object | - | - | -| rules | 表单验证规则,用法参考 [async-validator](https://github.com/yiminghe/async-validator) | object | - | - | -| labelWidth | label 宽度,可用任意 CSS 长度单位 | string | | -| labelPlacement | label 放置的位置 | string | 'right' \| 'left' \| 'top' | 'left' | -| placement | 是否横向排列 | string | 'horizontal' \| 'vertical' | 'vertical' | -| showColon | 是否显示冒号 | boolean | true \| false | true | +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| -------------- | ---------------------------------------------------------------------------------------- | ------- | -------------------------- | ---------- | +| initialValues | 表单默认值,只有初始化以及重置时生效;该值是不受控的,和表单中的 defaultValue 的作用相同 | object | - | - | +| rules | 表单验证规则,用法参考 [async-validator](https://github.com/yiminghe/async-validator) | object | - | - | +| labelWidth | label 宽度,可用任意 CSS 长度单位 | string | | +| labelPlacement | label 放置的位置 | string | 'right' \| 'left' \| 'top' | 'left' | +| placement | 是否横向排列 | string | 'horizontal' \| 'vertical' | 'vertical' | +| showColon | 是否显示冒号 | boolean | true \| false | true | ## Events @@ -87,7 +87,7 @@ import DemoUseForm from '../../demo/form/section-useForm.jsx' | -------------- | ------------------------ | -------------------------------------------------- | ------------------------------------------------------------- | ------ | | onValuesChange | 字段值更新时触发回调事件 | (changedValues: object, allValues: object) => void | changedValues: 改变的表单对象
allValues: 所有表单项对象 | - | -### SchemaForm +## SchemaForm > 继承 Form API @@ -97,14 +97,14 @@ import DemoUseForm from '../../demo/form/section-useForm.jsx' | submit | 继承 Form.Submit API | Object | - | - | | reset | 继承 Form.Reset API | Object | - | - | -### FormList +## FormList | 参数 | 说明 | 类型 | 可选值 | 默认值 | | -------- | -------- | ---------------------------------------------------------------- | ------ | ------ | | name | 列表名称 | String | - | - | | children | 渲染函数 | (fields: Field[], operation: { add, remove }) => React.ReactNode | - | - | -### Form.Item +## Form.Item | 参数 | 说明 | 类型 | 可选值 | 默认值 | | --------------- | --------------------------------------------------------------------------------------------------------------- | ------- | ---------------------------- | -------- | @@ -117,7 +117,7 @@ import DemoUseForm from '../../demo/form/section-useForm.jsx' | valuePropName | 子节点的值的属性,如 Switch Radio Checkbox 的是 'checked' | string | - | 'value' | | contentPosition | 指定显示内容的位置的位置,对一些非 HiUI 表单组件进行设置 | string | 'top' \| 'center' \|'bottom' | 'center' | -### SchemaItem +## SchemaItem > 继承 Form.Item API @@ -126,33 +126,33 @@ import DemoUseForm from '../../demo/form/section-useForm.jsx' | component | 用于渲染的组件名称,(现在组件名称,只限于 HiUI 中的组件名) | string | - | - | | componentProps | 组件的属性 | string | - | - | -### Form.Submit +## Form.Submit > 继承 Button API -| 参数 | 说明 | 类型 | 可选值 | 默认值 | -| -------- | -------------------------------------------------------------- | -------- | ------ | --------- | -| onClick | 点击提交后触发 Function(value: Object, errors: Object) => void | Function | - | func.noop | -| validate | 需要校验的 field 数组 | Array | - | - | +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| ------- | -------------------------------------------------------------- | -------- | ------ | --------- | +| onClick | 点击提交后触发 Function(value: Object, errors: Object) => void | Function | - | func.noop | +| fields | 需要校验的 field 字段,不传入的话就是默认全部校验 | Array | - | - | -### Form.Reset +## Form.Reset > 继承 Button API -| 参数 | 说明 | 类型 | 默认值 | -| --------- | ------------------------- | -------- | --------- | -| onClick | 点击提交后触发 () => void | Function | func.noop | -| fields | 自定义重置的字段 | Array | - | -| toDefault | 返回默认值 | Boolean | true | +| 参数 | 说明 | 类型 | 默认值 | +| --------- | ------------------------------------------------- | -------- | --------- | +| onClick | 点击提交后触发 () => void | Function | func.noop | +| fields | 需要重置的 field 字段,不传入的话就是默认全部重置 | Array | - | +| toDefault | 返回默认值 | Boolean | true | ## Methods -| 方法名 | 说明 | -| ------------------------------------------------------ | ------------------ | -| validate(callback: isValid => void) | 对整个表单进行校验 | -| validateField(field: string, callback: errors => void) | 对表单字段进行校验 | -| resetValidates() | 重置整个表单的验证 | -| setFieldsValue() | 设置表单的值 | +| 方法名 | 说明 | +| -------------------------------------------------------------------------- | ------------------------------------------------------------ | +| validate(callback: (fields: Object, errors: Object) => void, fields:Array) | 对整个表单进行校验, 对应 [Form.Submit](#Form.Submit)中的 API | +| validateField(fields: string, callback: errors => void) | 对指定表单字段进行校验 | +| resetValidates(callback:() => void, fields:Array, toDefault:boolean) | 重置整个表单的验证,对应 [Form.Reset](#Form.Reset)中的 API | +| setFieldsValue(field: Object) | 设置表单的值,在异步获取的数据回显的时候,使用该方法 | ## rules