Skip to content

Commit

Permalink
fix(core): fix reactions initial value will overwrite value (#2252)
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang committed Sep 29, 2021
1 parent 7185977 commit c4ca495
Show file tree
Hide file tree
Showing 18 changed files with 333 additions and 44 deletions.
30 changes: 30 additions & 0 deletions packages/core/src/__tests__/field.spec.ts
Expand Up @@ -1603,3 +1603,33 @@ test('state depend field visible value', async () => {
expect(cc.visible).toBeTruthy()
expect(cc.disabled).toBeFalsy()
})

test('reactions initialValue and value', () => {
const form = attach(
createForm({
values: {
aa: {
input: '111',
},
},
})
)
attach(
form.createObjectField({
name: 'aa',
reactions: [
(field) => {
field.initialValue = {}
field.initialValue.input = 123
},
],
})
)
attach(
form.createField({
name: 'input',
basePath: 'aa',
})
)
expect(form.values.aa.input).toEqual('111')
})
4 changes: 4 additions & 0 deletions packages/core/src/models/Field.ts
Expand Up @@ -59,6 +59,8 @@ import {
setLoading,
validateSelf,
getValidFieldDefaultValue,
initializeStart,
initializeEnd,
} from '../shared/internals'
import { Query } from './Query'
export class Field<
Expand Down Expand Up @@ -112,11 +114,13 @@ export class Field<
this.form = form
this.props = props
this.designable = designable
initializeStart()
this.makeIndexes(address)
this.initialize()
this.makeObservable()
this.makeReactive()
this.onInit()
initializeEnd()
}

protected makeIndexes(address: FormPathPattern) {
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/models/VoidField.ts
Expand Up @@ -19,6 +19,8 @@ import {
createStateGetter,
createStateSetter,
initFieldUpdate,
initializeStart,
initializeEnd,
} from '../shared/internals'
import { Form } from './Form'
import { Query } from './Query'
Expand Down Expand Up @@ -61,11 +63,13 @@ export class VoidField<Decorator = any, Component = any, TextType = any> {
this.form = form
this.props = props
this.designable = designable
initializeStart()
this.makeIndexes(address)
this.initialize()
this.makeObservable()
this.makeReactive()
this.onInit()
initializeEnd()
}

protected makeIndexes(address: FormPathPattern) {
Expand Down
37 changes: 19 additions & 18 deletions packages/core/src/shared/constants.ts
@@ -1,21 +1,21 @@
export const ReservedProperties = new Set([
'form',
'parent',
'props',
'caches',
'requests',
'disposers',
'heart',
'graph',
'indexes',
'fields',
'lifecycles',
'originValues',
'componentType',
'componentProps',
'decoratorType',
'decoratorProps',
])
export const ReservedProperties = {
form: true,
parent: true,
props: true,
caches: true,
requests: true,
disposers: true,
heart: true,
graph: true,
indexes: true,
fields: true,
lifecycles: true,
originValues: true,
componentType: true,
componentProps: true,
decoratorType: true,
decoratorProps: true,
}

export const RESPONSE_REQUEST_DURATION = 100

Expand All @@ -24,6 +24,7 @@ export const GlobalState = {
context: [],
effectStart: false,
effectEnd: false,
initializing: false,
}

export const NumberIndexReg = /^\.(\d+)/
25 changes: 17 additions & 8 deletions packages/core/src/shared/internals.ts
Expand Up @@ -49,6 +49,7 @@ import {
RESPONSE_REQUEST_DURATION,
ReservedProperties,
NumberIndexReg,
GlobalState,
} from './constants'

export const isHTMLInputEvent = (event: any, stopPropagation = true) => {
Expand Down Expand Up @@ -160,17 +161,15 @@ export const patchFormValues = (
if (allowAssignDefaultValue(targetValue, source)) {
update(path, source)
} else {
if (isEmpty(source)) return
if (GlobalState.initializing) return
if (isPlainObj(targetValue) && isPlainObj(source)) {
each(source, (value, key) => {
patch(value, path.concat(key))
})
} else if (!isEmpty(source)) {
} else {
if (targetField) {
if (
!isVoidField(targetField) &&
targetField.initialized &&
!targetField.modified
) {
if (!isVoidField(targetField) && !targetField.modified) {
update(path, source)
}
} else {
Expand Down Expand Up @@ -619,7 +618,7 @@ export const setModelState = (model: any, setter: any) => {
Object.keys(setter || {}).forEach((key: string) => {
const value = setter[key]
if (isFn(value)) return
if (ReservedProperties.has(key)) return
if (ReservedProperties[key]) return
if (isSkipProperty(key)) return
model[key] = value
})
Expand All @@ -636,7 +635,7 @@ export const getModelState = (model: any, getter?: any) => {
if (isFn(value)) {
return buf
}
if (ReservedProperties.has(key)) return buf
if (ReservedProperties[key]) return buf
if (key === 'address' || key === 'path') {
buf[key] = value.toString()
return buf
Expand Down Expand Up @@ -1023,3 +1022,13 @@ export const createReactions = (field: GeneralField) => {
})
})
}

export const initializeStart = () => {
GlobalState.initializing = true
}

export const initializeEnd = () => {
batch.endpoint(() => {
GlobalState.initializing = false
})
}
136 changes: 136 additions & 0 deletions packages/json-schema/src/__tests__/server-validate.spec.ts
@@ -0,0 +1,136 @@
import { createForm, Form } from '@formily/core'
import { ISchema, Schema, SchemaKey } from '../'

// 这是schema
const schemaJson = {
type: 'object',
title: 'xxx配置',
properties: {
string: {
type: 'string',
title: 'string',
maxLength: 5,
required: true,
},
number: {
type: 'number',
title: 'number',
required: true,
},
url: {
type: 'string',
title: 'url',
format: 'url',
},
arr: {
type: 'array',
title: 'array',
maxItems: 2,
required: true,
items: {
type: 'object',
properties: {
string: {
type: 'string',
title: 'string',
required: true,
},
},
},
},
},
}
// 这是需要校验的数据
const schemaData = {
string: '123456', // 超过5个字
// number 字段不存在
url: 'xxxxx', // 不合法的url
arr: [
{
string: '1',
},
{
string: '2',
},
{
// 数组超出2项
string: '', // 没有填
},
],
}

function recursiveField(
form: Form,
schema: ISchema,
basePath?: string,
name?: SchemaKey
) {
const fieldSchema = new Schema(schema)
const fieldProps = fieldSchema.toFieldProps()

function recursiveProperties(propBasePath?: string) {
fieldSchema.mapProperties((propSchema, propName) => {
recursiveField(form, propSchema, propBasePath, propName)
})
}

if (name === undefined || name === null) {
recursiveProperties(basePath)
return
}

if (schema.type === 'object') {
const field = form.createObjectField({
...fieldProps,
name,
basePath,
})

recursiveProperties(field.address.toString())
} else if (schema.type === 'array') {
const field = form.createArrayField({
...fieldProps,
name,
basePath,
})

const fieldAddress = field.address.toString()
const fieldValues = form.getValuesIn(fieldAddress)
fieldValues.forEach((value: any, index: number) => {
if (schema.items) {
const itemsSchema = Array.isArray(schema.items)
? schema.items[index] || schema.items[0]
: schema.items

recursiveField(form, itemsSchema as ISchema, fieldAddress, index)
}
})
} else if (schema.type === 'void') {
const field = form.createVoidField({
...fieldProps,
name,
basePath,
})

recursiveProperties(field.address.toString())
} else {
form.createField({
...fieldProps,
name,
basePath,
})
}
}
test('server validate', async () => {
const form = createForm({
values: schemaData,
})
recursiveField(form, schemaJson)
let errors: any[]
try {
await form.validate()
} catch (e) {
errors = e
}
expect(errors).not.toBeUndefined()
})
12 changes: 11 additions & 1 deletion packages/json-schema/src/__tests__/traverse.spec.ts
Expand Up @@ -8,12 +8,20 @@ test('traverseSchema', () => {
type: 'string',
required: true,
'x-validator': 'phone',
default: {
input: 123,
},
},
(value, path) => {
visited.push(path)
}
)
expect(visited).toEqual([['x-validator'], ['type'], ['required']])
expect(visited).toEqual([
['x-validator'],
['type'],
['required'],
['default'],
])
})

test('traverse circular reference', () => {
Expand All @@ -33,6 +41,7 @@ test('traverse circular reference', () => {
}
a.dd.mm = a
traverse(a, () => {})
traverseSchema(a as any, () => {})
})

test('traverse none circular reference', () => {
Expand All @@ -50,6 +59,7 @@ test('traverse none circular reference', () => {
traverse(a, (value, path) => {
paths.push(path)
})
traverseSchema(a, () => {})
expect(
paths.some((path) => FormPath.parse(path).includes('dd.mm'))
).toBeTruthy()
Expand Down

0 comments on commit c4ca495

Please sign in to comment.