Skip to content

Commit

Permalink
Merge pull request #1644 from XiaoMi/hotfix/#1642
Browse files Browse the repository at this point in the history
Hotfix/#1642
  • Loading branch information
chownchen authored Mar 17, 2021
2 parents d711e96 + e614634 commit e6bf4a1
Show file tree
Hide file tree
Showing 11 changed files with 291 additions and 210 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# 更新日志

# 3.5.1
- 修复 `Form` 组件 setFieldsValue 方式调用显示异常问题 [#1642](https://github.com/XiaoMi/hiui/issues/1642)
- 修复 `Table` 组件 data值为带正负符号的数字类型字符串时,无法进行求和及平均值的问题 [#1616](https://github.com/XiaoMi/hiui/issues/1616)

## 3.5.0
Expand Down
99 changes: 56 additions & 43 deletions components/form/Form.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useEffect, useCallback, useReducer, forwardRef, useRef } from 'react'
import React, { useCallback, useReducer, forwardRef, useRef, useImperativeHandle } from 'react'
import _ from 'lodash'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import Immutable, { FILEDS_UPDATE, FILEDS_UPDATE_LIST } from './FormReducer'
import Immutable, { FILEDS_UPDATE, FILEDS_UPDATE_LIST, FILEDS_UPDATE_STATE, FILEDS_REMOVE_LIST } from './FormReducer'
import FormContext from './FormContext'
import { transformValues } from './utils'

Expand All @@ -24,7 +24,7 @@ const InternalForm = (props) => {
children,
className,
style,
innerRef: formRef,
innerRef: formRef = useRef(),
initialValues,
onValuesChange,
updateFormSchema,
Expand All @@ -38,11 +38,12 @@ const InternalForm = (props) => {
...props
})

const { fields, listNames, listValues } = state
const { fields, listNames, listValues } = _Immutable.current.currentState()
// 用户手动设置表单数据
const setFieldsValue = useCallback(
(values) => {
const _fields = _Immutable.current.currentStateFields()
const { listNames, listValues } = _Immutable.current.currentState()
_fields.forEach((item) => {
const { field } = item
// eslint-disable-next-line no-prototype-builtins
Expand All @@ -52,26 +53,30 @@ const InternalForm = (props) => {
item.setValue(value)
}
})
dispatch({
_Immutable.current.setState({
type: FILEDS_UPDATE,
payload: _fields.filter((item) => {
return item._type !== 'list'
})
})
// 处理 list value
Object.keys(values).forEach((key) => {
listNames.includes(key) &&
dispatch({
if (listNames.includes(key)) {
_Immutable.current.setState({ type: FILEDS_REMOVE_LIST, payload: key })
_Immutable.current.setState({
type: FILEDS_UPDATE_LIST,
payload: Object.assign({}, { ...listValues }, { [key]: values[key] })
})
}
})
dispatch({ type: FILEDS_UPDATE_STATE })
},
[fields, listValues]
[fields, listValues, listNames, _Immutable]
)
// 转换值的输出
const internalValuesChange = useCallback(
(changeValues, allValues) => {
const fields = _Immutable.current.currentStateFields()
const _transformValues = transformValues(allValues, fields)
const _changeValues = _.cloneDeep(changeValues)

Expand All @@ -93,40 +98,54 @@ const InternalForm = (props) => {
const resetValidates = useCallback(
(cb, resetNames, toDefault) => {
const changeValues = {}
const cacheallValues = {}
let _fields = _.cloneDeep(fields)
fields.forEach((item) => {
const { field, value } = item
cacheallValues[field] = value
})

const allValues = {}
let _fields = _Immutable.current.currentStateFields()
const { listNames, listValues } = _Immutable.current.currentState()
_fields = _fields.filter((childrenField) => {
return Array.isArray(resetNames) ? resetNames.includes(childrenField.field) : true
})

_fields.forEach((childrenField) => {
const value =
toDefault && initialValues && initialValues[childrenField.field] ? initialValues[childrenField.field] : ''
if (!_.isEqual(childrenField.value, value)) {
changeValues[childrenField.field] = value
_fields.forEach((item) => {
const { field, listname } = item
const changeFieldkey = listname || field
const isToDefault = toDefault && initialValues && typeof initialValues[changeFieldkey] !== 'undefined'
const value = isToDefault ? initialValues[field] : ''
const changeFieldVal = isToDefault ? initialValues[changeFieldkey] : ''
changeValues[changeFieldkey] = changeFieldVal
allValues[changeFieldVal] = value
item.value = value
item.setValue(value)
item.resetValidate(value)
})
_Immutable.current.setState({
type: FILEDS_UPDATE,
payload: _fields.filter((item) => {
return item._type !== 'list'
})
})
// 处理 list value
Object.keys(initialValues || {}).forEach((key) => {
if (listNames.includes(key)) {
_Immutable.current.setState({ type: FILEDS_REMOVE_LIST, payload: key })
_Immutable.current.setState({
type: FILEDS_UPDATE_LIST,
payload: Object.assign({}, { ...listValues }, { [key]: initialValues[key] })
})
}

childrenField.value = value
childrenField.resetValidate(value)
})
dispatch({ type: FILEDS_UPDATE, payload: _fields })
dispatch({ type: FILEDS_UPDATE_STATE })
cb instanceof Function && cb()
// 比较耗性能
internalValuesChange(changeValues, Object.assign({}, { ...cacheallValues }, { ...changeValues }))
onValuesChange && onValuesChange(changeValues, changeValues)
},
[fields, initialValues, onValuesChange, internalValuesChange]
[fields, initialValues, onValuesChange, internalValuesChange, listNames, _Immutable]
)
// 对整个表单进行校验
const validate = useCallback(
(cb, validateNames) => {
const values = {}
let errors = {}

const fields = _.cloneDeep(_Immutable.current.currentStateFields())
if (fields.length === 0 && cb) {
cb(values, errors)
return
Expand Down Expand Up @@ -157,12 +176,13 @@ const InternalForm = (props) => {

cb && cb(transformValues(values, _fields), errors)
},
[fields]
[fields, _Immutable]
)

const validateField = useCallback(
(key, cb) => {
let value
const fields = _.cloneDeep(_Immutable.current.currentStateFields())
const field = fields.filter((fieldChild) => {
if (fieldChild.field === key) {
value = fieldChild.value
Expand All @@ -182,22 +202,15 @@ const InternalForm = (props) => {
value
)
},
[fields]
[fields, _Immutable]
)

useEffect(() => {
if (!formRef) {
return
}
formRef.current = {
resetValidates,
validateField,
validate,
setFieldsValue,
updateFormSchema
}
}, [fields])

useImperativeHandle(formRef, () => ({
resetValidates,
validateField,
validate,
setFieldsValue,
updateFormSchema
}))
return (
<form
className={classNames('hi-form', className, getClassNames(props))}
Expand Down
62 changes: 44 additions & 18 deletions components/form/FormReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,71 @@ 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'
export const FILEDS_REMOVE_LIST = 'FILEDS_REMOVE_LIST'
export const FILEDS_UPDATE_STATE = 'FILEDS_UPDATE_STATE'
export default class Immutable {
constructor() {
this.state = {}
this.SyncState = { fields: [], listNames: [], listValues: {} }
}

FormReducer = (state, action) => {
switch (action.type) {
case FILEDS_UPDATE_STATE:
return this.SyncState
default:
this.SyncState = state
return state
}
}

setState(action) {
const SyncState = this.SyncState
switch (action.type) {
case FILEDS_INIT:
const { fields } = state
const { fields } = SyncState
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:
this.state.fields = [...action.payload]
return Object.assign({}, { ...state }, { fields: [...action.payload] })
this.SyncState = _.cloneDeep(Object.assign({}, { ...SyncState }, { fields: initfields.concat(action.payload) }))
return this.SyncState
case FILEDS_REMOVE:
const _fields = state.fields.filter((item) => {
const _fields = SyncState.fields.filter((item) => {
return action.payload !== item.field && action.payload !== item.propsField
})
this.state = Object.assign({}, { ...state }, { fields: _fields })
return this.state
this.SyncState = _.cloneDeep(Object.assign({}, { ...SyncState }, { fields: _fields }))
return this.SyncState
case FILEDS_REMOVE_LIST:
const notIncludesListFields = SyncState.fields.filter((item) => {
return action.payload !== item.listname
})
this.SyncState.fields = notIncludesListFields
if (this.SyncState.listValues[action.payload]) {
this.SyncState.listValues[action.payload] = []
}
return this.SyncState
case FILEDS_UPDATE:
this.SyncState = _.cloneDeep(Object.assign({}, { ...SyncState }, { fields: [...action.payload] }))
return this.SyncState
case FILEDS_INIT_LIST:
const { listNames } = state
const { listNames } = SyncState
!listNames.includes(action.payload) && listNames.push(action.payload)
this.state = Object.assign({}, { ...state }, { listNames: listNames })

return this.state
this.SyncState = _.cloneDeep(Object.assign({}, { ...SyncState }, { listNames: listNames }))
return this.SyncState
case FILEDS_UPDATE_LIST:
this.state = Object.assign({}, { ...state }, { listValues: action.payload })
return this.state
this.SyncState = _.cloneDeep(Object.assign({}, { ...SyncState }, { listValues: action.payload }))
return this.SyncState
default:
this.state = state
return state
this.SyncState = SyncState
return SyncState
}
}

currentStateFields() {
return _.cloneDeep(this.state.fields)
return _.cloneDeep(this.SyncState.fields)
}

currentState() {
return _.cloneDeep(this.SyncState)
}
}
Loading

0 comments on commit e6bf4a1

Please sign in to comment.