Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions packages/core/src/__tests__/array.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1122,3 +1122,43 @@ test('record: find form fields', () => {

expect(array.record).toEqual({ array: [{ a: 1 }, { a: 2 }] })
})

test('array field splice array state should not destory unexpected field', () => {
const form = attach(
createForm({
initialValues: {
array: [{ a: 1 }, { a: 2 }, { a: 3 }],
},
})
)

const array = attach(
form.createArrayField({
name: 'array',
})
)
attach(
form.createField({
name: '0',
basePath: 'array',
})
)
attach(
form.createField({
name: '1',
basePath: 'array',
})
)
attach(
form.createField({
name: '2',
basePath: 'array',
})
)

array.remove(0)

array.remove(0)

expect(Object.keys(form.fields)).toEqual(['array', 'array.0'])
})
74 changes: 59 additions & 15 deletions packages/core/src/shared/internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,17 @@ export const patchFieldStates = (
) => {
patches.forEach(({ type, address, oldAddress, payload }) => {
if (type === 'remove') {
destroy(target, address, false)
if (payload) {
// When a payload is passed, the node should be deleted. However, the address may still be used.
// To avoid affecting the address order, set address to undefined.
destroyField(payload, false)
if (target[address] === payload) {
target[address] = undefined
}
} else {
// If only the address is passed without the payload, it means that the address is no longer used, so remove the address directly
delete target[address]
}
} else if (type === 'update') {
if (payload) {
target[address] = payload
Expand All @@ -169,18 +179,24 @@ export const patchFieldStates = (
})
}

export const destroyField = (field: GeneralField, forceClear = true) => {
field.dispose()
if (isDataField(field) && forceClear) {
const form = field.form
const path = field.path
form.deleteValuesIn(path)
form.deleteInitialValuesIn(path)
}
}

export const destroy = (
target: Record<string, GeneralField>,
address: string,
forceClear = true
) => {
const field = target[address]
field?.dispose()
if (isDataField(field) && forceClear) {
const form = field.form
const path = field.path
form.deleteValuesIn(path)
form.deleteInitialValuesIn(path)
if (field) {
destroyField(field, forceClear)
}
delete target[address]
}
Expand Down Expand Up @@ -383,19 +399,27 @@ export const spliceArrayState = (
return index >= startIndex && index < startIndex + insertCount
}
const isDeleteNode = (identifier: string) => {
const afterStr = identifier.substring(addrLength)
const number = afterStr.match(NumberIndexReg)?.[1]
if (number === undefined) return false
const index = Number(number)
return index >= startIndex && index < startIndex + deleteCount
}

const isNeedCleanupNode = (identifier: string) => {
const preStr = identifier.substring(0, addrLength)
const afterStr = identifier.substring(addrLength)
const number = afterStr.match(NumberIndexReg)?.[1]
if (number === undefined) return false
const index = Number(number)
return (
(index > startIndex &&
!fields[
`${preStr}${afterStr.replace(/^\.\d+/, `.${index + deleteCount}`)}`
]) ||
index === startIndex
index >= startIndex &&
!fields[
`${preStr}${afterStr.replace(/^\.\d+/, `.${index + deleteCount}`)}`
]
)
}

const moveIndex = (identifier: string) => {
if (offset === 0) return identifier
const preStr = identifier.substring(0, addrLength)
Expand All @@ -417,9 +441,29 @@ export const spliceArrayState = (
oldAddress: identifier,
payload: field,
})
}
if (isInsertNode(identifier) || isDeleteNode(identifier)) {
fieldPatches.push({ type: 'remove', address: identifier })
if (isNeedCleanupNode(identifier)) {
fieldPatches.push({
type: 'remove',
address: identifier,
})
}
} else if (isInsertNode(identifier)) {
fieldPatches.push({
type: 'remove',
address: identifier,
})
} else if (isDeleteNode(identifier)) {
fieldPatches.push({
type: 'remove',
address: identifier,
payload: field,
})
if (isNeedCleanupNode(identifier)) {
fieldPatches.push({
type: 'remove',
address: identifier,
})
}
}
}
})
Expand Down
Loading