Skip to content

Commit

Permalink
fix(core): fix array unshift with incomplete elements (#2150)
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang authored Sep 13, 2021
1 parent f621d98 commit 6463371
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 34 deletions.
13 changes: 5 additions & 8 deletions packages/antd/src/array-table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ const ArrayTablePagination: React.FC<IArrayTablePaginationProps> = (props) => {
)
}

const RowComp = (props: any) => {
return <SortableRow index={props['data-row-key'] || 0} {...props} />
}

export const ArrayTable: ComposedArrayTable = observer(
(props: TableProps<any>) => {
const ref = useRef<HTMLDivElement>()
Expand Down Expand Up @@ -305,14 +309,7 @@ export const ArrayTable: ComposedArrayTable = observer(
{...props}
/>
),
row: (props: any) => {
return (
<SortableRow
index={props['data-row-key'] || 0}
{...props}
/>
)
},
row: RowComp,
},
}}
/>
Expand Down
47 changes: 47 additions & 0 deletions packages/core/src/__tests__/array.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,50 @@ test('nest array remove', async () => {
await metrics.remove(1)
expect(form.fields['metrics.0.content.0.attr']).not.toBeUndefined()
})

test('incomplete insertion of array elements', async () => {
const form = attach(
createForm({
values: {
array: [{ aa: 1 }, { aa: 2 }, { aa: 3 }],
},
})
)
const array = attach(
form.createArrayField({
name: 'array',
})
)
attach(
form.createObjectField({
name: '0',
basePath: 'array',
})
)
attach(
form.createField({
name: 'aa',
basePath: 'array.0',
})
)
attach(
form.createObjectField({
name: '2',
basePath: 'array',
})
)
attach(
form.createField({
name: 'aa',
basePath: 'array.2',
})
)
expect(form.fields['array.0.aa']).not.toBeUndefined()
expect(form.fields['array.1.aa']).toBeUndefined()
expect(form.fields['array.2.aa']).not.toBeUndefined()
await array.unshift({})
expect(form.fields['array.0.aa']).toBeUndefined()
expect(form.fields['array.1.aa']).not.toBeUndefined()
expect(form.fields['array.2.aa']).toBeUndefined()
expect(form.fields['array.3.aa']).not.toBeUndefined()
})
2 changes: 2 additions & 0 deletions packages/core/src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ export const GlobalState = {
effectStart: false,
effectEnd: false,
}

export const NumberIndexReg = /^\.(\d+)/
51 changes: 26 additions & 25 deletions packages/core/src/shared/internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
FieldMatchPattern,
} from '../types'
import { isArrayField, isGeneralField, isQuery, isVoidField } from './externals'
import { ReservedProperties, GlobalState } from './constants'
import { ReservedProperties, GlobalState, NumberIndexReg } from './constants'

export const isHTMLInputEvent = (event: any, stopPropagation = true) => {
if (event?.target) {
Expand Down Expand Up @@ -104,13 +104,14 @@ export const applyFieldPatches = (
target: Record<string, GeneralField>,
patches: INodePatch<GeneralField>[]
) => {
patches.forEach(({ type, address, payload }) => {
patches.forEach(({ type, address, oldAddress, payload }) => {
if (type === 'remove') {
target[address].dispose()
target[address]?.dispose()
delete target[address]
} else if (type === 'update') {
if (payload) {
target[address] = payload
if (target[oldAddress] === payload) delete target[oldAddress]
}
if (address && payload) {
buildNodeIndexes(payload, address)
Expand Down Expand Up @@ -228,32 +229,31 @@ export const spliceArrayState = (
...props,
}
const address = field.address.toString()
const addrLength = address.length
const fields = field.form.fields
const fieldPatches: INodePatch<GeneralField>[] = []
const offset = insertCount - deleteCount
const isArrayChildren = (identifier: string) => {
return (
identifier.indexOf(address) === 0 && identifier.length > address.length
)
return identifier.indexOf(address) === 0 && identifier.length > addrLength
}
const isAfterNode = (identifier: string) => {
const afterStr = identifier.slice(address.length)
const number = afterStr.match(/^\.(\d+)/)?.[1]
const afterStr = identifier.substring(addrLength)
const number = afterStr.match(NumberIndexReg)?.[1]
if (number === undefined) return false
const index = Number(number)
return index > startIndex + deleteCount - 1
}
const isInsertNode = (identifier: string) => {
const afterStr = identifier.slice(address.length)
const number = afterStr.match(/^\.(\d+)/)?.[1]
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 + insertCount
}
const isDeleteNode = (identifier: string) => {
const preStr = identifier.slice(0, address.length)
const afterStr = identifier.slice(address.length)
const number = afterStr.match(/^\.(\d+)/)?.[1]
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 (
Expand All @@ -265,9 +265,9 @@ export const spliceArrayState = (
}
const moveIndex = (identifier: string) => {
if (offset === 0) return identifier
const preStr = identifier.slice(0, address.length)
const afterStr = identifier.slice(address.length)
const number = afterStr.match(/^\.(\d+)/)?.[1]
const preStr = identifier.substring(0, addrLength)
const afterStr = identifier.substring(addrLength)
const number = afterStr.match(NumberIndexReg)?.[1]
if (number === undefined) return identifier
const index = Number(number) + offset
return `${preStr}${afterStr.replace(/^\.\d+/, `.${index}`)}`
Expand All @@ -281,6 +281,7 @@ export const spliceArrayState = (
fieldPatches.push({
type: 'update',
address: newIdentifier,
oldAddress: identifier,
payload: field,
})
}
Expand All @@ -305,25 +306,24 @@ export const exchangeArrayState = (
}
const address = field.address.toString()
const fields = field.form.fields
const addrLength = address.length
const fieldPatches: INodePatch<GeneralField>[] = []
const isArrayChildren = (identifier: string) => {
return (
identifier.indexOf(address) === 0 && identifier.length > address.length
)
return identifier.indexOf(address) === 0 && identifier.length > addrLength
}

const isFromOrToNode = (identifier: string) => {
const afterStr = identifier.slice(address.length)
const number = afterStr.match(/^\.(\d+)/)?.[1]
const afterStr = identifier.substring(addrLength)
const number = afterStr.match(NumberIndexReg)?.[1]
if (number === undefined) return false
const index = Number(number)
return index === toIndex || index === fromIndex
}

const moveIndex = (identifier: string) => {
const preStr = identifier.slice(0, address.length)
const afterStr = identifier.slice(address.length)
const number = afterStr.match(/^\.(\d+)/)[1]
const preStr = identifier.substring(0, addrLength)
const afterStr = identifier.substring(addrLength)
const number = afterStr.match(NumberIndexReg)[1]
const current = Number(number)
let index = current
if (index === fromIndex) {
Expand All @@ -343,6 +343,7 @@ export const exchangeArrayState = (
fieldPatches.push({
type: 'update',
address: newIdentifier,
oldAddress: identifier,
payload: field,
})
if (!fields[newIdentifier]) {
Expand Down Expand Up @@ -371,7 +372,7 @@ export const cleanupArrayChildren = (field: ArrayField, start: number) => {

const isNeedCleanup = (identifier: string) => {
const afterStr = identifier.slice(address.length)
const number = afterStr.match(/^\.(\d+)/)?.[1]
const number = afterStr.match(NumberIndexReg)?.[1]
if (number === undefined) return false
const index = Number(number)
return index >= start
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export type HeartSubscriber = ({
export interface INodePatch<T> {
type: 'remove' | 'update'
address: string
oldAddress?: string
payload?: T
}

Expand Down
1 change: 0 additions & 1 deletion packages/react/src/components/ObjectField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export const ObjectField = <D extends JSXComponent, C extends JSXComponent>(
const field = useAttach(
form.createObjectField({ basePath: parent?.address, ...props })
)

return (
<FieldContext.Provider value={field}>
<ReactiveField field={field}>{props.children}</ReactiveField>
Expand Down

0 comments on commit 6463371

Please sign in to comment.