Skip to content

Commit

Permalink
fix(@uform/core): fix alibaba#613 and alibaba#615
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang committed Jan 18, 2020
1 parent 01c6c76 commit a5fb1ac
Show file tree
Hide file tree
Showing 15 changed files with 289 additions and 53 deletions.
109 changes: 109 additions & 0 deletions packages/core/src/__tests__/__snapshots__/index.spec.ts.snap

Large diffs are not rendered by default.

45 changes: 36 additions & 9 deletions packages/core/src/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,33 @@ describe('createForm', () => {
expect(form.getFormGraph()).toMatchSnapshot()
})

const sleep = (d=1000)=>new Promise((resolve)=>{
setTimeout(()=>{
resolve()
},d)
})

test('invalid initialValue will not trigger validate', async () => {
const form = createForm()
const field = form.registerField({
name: 'aa',
rules:[{
required:true
}]
})
const mutators = form.createMutators(field)
field.subscribe(() => {
mutators.validate({ throwErrors: false })
})
form.setFormState(state => {
state.initialValues = {
aa: null
}
})
await sleep(10)
expect(field.getState(state=>state.errors).length).toEqual(1)
})

test('lifecycles', () => {
const onFormInit = jest.fn()
const onFieldInit = jest.fn()
Expand Down Expand Up @@ -437,9 +464,9 @@ describe('clearErrors', () => {
expect(form.getFormState(state => state.errors)).toEqual([])
})

test('wildcard path', async () => { })
test('wildcard path', async () => {})

test('effect', async () => { })
test('effect', async () => {})
})

describe('validate', () => {
Expand Down Expand Up @@ -487,7 +514,7 @@ describe('validate', () => {

try {
await form.submit()
} catch (e) { }
} catch (e) {}
expect(onValidateFailedTrigger).toBeCalledTimes(1)
})

Expand Down Expand Up @@ -515,7 +542,7 @@ describe('validate', () => {
}) // CustomValidator error
try {
await form.submit()
} catch (e) { }
} catch (e) {}
expect(onValidateFailedTrigger).toBeCalledTimes(1)
})

Expand Down Expand Up @@ -1560,16 +1587,16 @@ describe('major sences', () => {
expect(form.getFormGraph()).toMatchSnapshot()
})

test('visible onChange',()=>{
test('visible onChange', () => {
const onChangeHandler = jest.fn()
const form = createForm({
initialValues:{
aa:123
initialValues: {
aa: 123
},
onChange:onChangeHandler
onChange: onChangeHandler
})
form.registerField({
name:'aa'
name: 'aa'
})
form.setFieldState('aa', state => {
state.visible = false
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ export function createForm<FieldProps, VirtualFieldProps>(
state.initialValue = initialValue
if (!isValid(state.value)) {
state.value = initialValue
} else if (
state.dataType === 'array' &&
state.value &&
state.value.length === 0
) {
state.value = initialValue
}
}
}
Expand Down Expand Up @@ -441,6 +447,7 @@ export function createForm<FieldProps, VirtualFieldProps>(
visible,
display,
computeState,
dataType,
useDirty,
props
}: Exclude<IFieldStateProps, 'dataPath' | 'nodePath'>): IField {
Expand All @@ -455,6 +462,7 @@ export function createForm<FieldProps, VirtualFieldProps>(
nodePath,
dataPath,
computeState,
dataType,
useDirty: isValid(useDirty) ? useDirty : options.useDirty
})
field.subscription = {
Expand Down
51 changes: 46 additions & 5 deletions packages/core/src/shared/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
Subscribable,
FormPath,
FormPathPattern,
isValid
isValid,
toArr
} from '@uform/shared'
import produce, { Draft, setAutoFreeze } from 'immer'
import {
Expand All @@ -21,6 +22,18 @@ const hasProxy = !!globalThisPolyfill.Proxy

setAutoFreeze(false)

const defaults = (...args:any[]):any=>{
const result = {}
each(args,(target)=>{
each(target,(value,key)=>{
if(isValid(value)){
result[key] = value
}
})
})
return result
}

export const createStateModel = <State = {}, Props = {}>(
Factory: IStateModelFactory<State, Props>
): IStateModelProvider<State, Props> => {
Expand All @@ -32,6 +45,7 @@ export const createStateModel = <State = {}, Props = {}>(
useDirty?: boolean
computeState?: (draft: State, prevState: State) => void
}
public cacheProps?: any
public displayName?: string
public dirtyNum: number
public dirtys: StateDirtyMap<State>
Expand All @@ -44,10 +58,7 @@ export const createStateModel = <State = {}, Props = {}>(
super()
this.state = { ...Factory.defaultState }
this.prevState = { ...Factory.defaultState }
this.props = {
...Factory.defaultProps,
...defaultProps
}
this.props = defaults(Factory.defaultProps,defaultProps)
this.dirtys = {}
this.dirtyNum = 0
this.stackCount = 0
Expand Down Expand Up @@ -100,6 +111,36 @@ export const createStateModel = <State = {}, Props = {}>(
}
}

watchProps = <T extends { [key: string]: any }>(
props: T,
keys: string[],
callback: (
changedProps: {
[key: string]: any
},
props?: T
) => void
) => {
if (!this.cacheProps) {
this.cacheProps = { ...props }
} else {
let changeNum = 0
let changedProps = {}
toArr(keys).forEach((key: string) => {
if (!isEqual(this.cacheProps[key], props[key])) {
changeNum++
changedProps[key] = props[key]
}
})
if (changeNum > 0) {
if (isFn(callback)) {
callback(changedProps, props)
}
this.cacheProps = { ...props }
}
}
}

setState = (
callback: (state: State | Draft<State>) => State | void,
silent = false
Expand Down
15 changes: 13 additions & 2 deletions packages/core/src/state/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const FieldState = createStateModel<IFieldState, IFieldStateProps>(
static defaultState = {
name: '',
path: '',
dataType: 'any',
initialized: false,
pristine: true,
valid: true,
Expand Down Expand Up @@ -42,7 +43,8 @@ export const FieldState = createStateModel<IFieldState, IFieldStateProps>(
}

static defaultProps = {
path: ''
path: '',
dataType: 'any'
}

private state: IFieldState
Expand All @@ -57,6 +59,7 @@ export const FieldState = createStateModel<IFieldState, IFieldStateProps>(
this.dataPath = FormPath.getPath(props.dataPath)
this.state.name = this.dataPath.entire
this.state.path = this.nodePath.entire
this.state.dataType = props.dataType || 'any'
}

readValues({ value, values }: IFieldStateProps) {
Expand All @@ -68,9 +71,17 @@ export const FieldState = createStateModel<IFieldState, IFieldStateProps>(
values = toArr(value)
}
}

values = toArr(values)

if(this.state.dataType === 'array'){
value = toArr(value)
values[0] = toArr(values[0])
}

return {
value,
values: toArr(values)
values
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/state/virtual-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ export const VirtualFieldState = createStateModel<
}

computeState(draft: IVirtualFieldState, prevState: IVirtualFieldState) {
if (draft.mounted === true) {
if (draft.mounted === true && draft.mounted !== prevState.mounted) {
draft.unmounted = false
}
if (!isValid(draft.props)) {
draft.props = prevState.props
}
if (draft.unmounted === true) {
if (draft.unmounted === true && draft.unmounted !== prevState.unmounted) {
draft.mounted = false
}
}
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export interface IStateModelProvider<S, P> {

export interface IFieldState<FieldProps = any> {
displayName?: string
dataType: string
name: string
path: string
initialized: boolean
Expand Down Expand Up @@ -159,6 +160,7 @@ export interface IFieldStateProps<FieldProps = any> {
path?: FormPathPattern
nodePath?: FormPathPattern
dataPath?: FormPathPattern
dataType?: string
name?: string
value?: any
values?: any[]
Expand All @@ -170,6 +172,7 @@ export interface IFieldStateProps<FieldProps = any> {
visible?: boolean
display?: boolean
useDirty?: boolean
useListMode?: boolean
computeState?: (draft: IFieldState, prevState: IFieldState) => void
}

Expand Down Expand Up @@ -322,6 +325,16 @@ export interface IModel<S = {}, P = {}> extends Subscribable {
setState: (callback?: (state: S | Draft<S>) => void, silent?: boolean) => void
getSourceState: (callback?: (state: S) => any) => any
setSourceState: (callback?: (state: S) => void) => void
watchProps: <T extends { [key: string]: any }>(
props: T,
keys: string[],
callback: (
changedProps: {
[key: string]: any
},
props: T
) => void
) => void
hasChanged: (path?: FormPathPattern) => boolean
isDirty: (key?: string) => boolean
getDirtyInfo: () => StateDirtyMap<S>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Object {
},
"aa": Object {
"active": false,
"dataType": "string",
"display": true,
"displayName": "FieldState",
"editable": true,
Expand Down Expand Up @@ -121,6 +122,7 @@ Object {
},
"NO_NAME_FIELD_$0.aa": Object {
"active": false,
"dataType": "string",
"display": true,
"displayName": "FieldState",
"editable": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Object {
},
"aa": Object {
"active": false,
"dataType": "string",
"display": true,
"displayName": "FieldState",
"editable": true,
Expand Down Expand Up @@ -96,6 +97,7 @@ Object {
},
"aa": Object {
"active": false,
"dataType": "string",
"display": true,
"displayName": "FieldState",
"editable": true,
Expand Down Expand Up @@ -181,6 +183,7 @@ Object {
},
"cc.aa": Object {
"active": false,
"dataType": "string",
"display": true,
"displayName": "FieldState",
"editable": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const SchemaField: React.FunctionComponent<ISchemaFieldProps> = (
path={path}
initialValue={fieldSchema.default}
props={fieldSchema.getSelfProps()}
dataType={fieldSchema.type}
triggerType={fieldSchema.getExtendsTriggerType()}
editable={fieldSchema.getExtendsEditable()}
visible={fieldSchema.getExtendsVisible()}
Expand Down
17 changes: 17 additions & 0 deletions packages/react/src/components/FieldList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'
import { IFieldStateUIProps } from '../types'
import { Field } from './Field'

export const FieldList: React.FC<IFieldStateUIProps> = props => {
return React.createElement(Field, {
...props,
dataType: 'array'
})
}

FieldList.displayName = 'ReactInternalFieldList'

FieldList.defaultProps = {
path: '',
triggerType: 'onChange'
}
2 changes: 1 addition & 1 deletion packages/react/src/hooks/useDirty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { isEqual } from '@uform/shared'

export const useDirty = (input: any = {}, keys: string[] = []) => {
const ref = React.useRef<any>({ data: {...input}, dirtys: {}, num: 0 })
const ref = React.useRef<any>({ data: { ...input }, dirtys: {}, num: 0 })
ref.current.num = 0
keys.forEach(key => {
if (!isEqual(input[key], ref.current.data[key])) {
Expand Down
Loading

0 comments on commit a5fb1ac

Please sign in to comment.