Skip to content

Commit 60e4c68

Browse files
committed
add baseStore to fieldApi
1 parent ee4b55c commit 60e4c68

File tree

3 files changed

+66
-5
lines changed

3 files changed

+66
-5
lines changed

packages/form-core/src/FieldApi.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Derived, batch } from '@tanstack/store'
1+
import { Derived, Store, batch } from '@tanstack/store'
22
import {
33
isStandardSchemaValidator,
44
standardSchemaValidators,
@@ -864,6 +864,10 @@ export type AnyFieldMeta = FieldMeta<
864864
any
865865
>
866866

867+
export type FieldBaseState<TParentData, TName extends DeepKeys<TParentData>> = {
868+
name: TName
869+
}
870+
867871
/**
868872
* An object type representing the state of a field.
869873
*/
@@ -1052,7 +1056,9 @@ export class FieldApi<
10521056
/**
10531057
* The field name.
10541058
*/
1055-
name!: DeepKeys<TParentData>
1059+
get name(): DeepKeys<TParentData> {
1060+
return this.baseStore.state.name
1061+
}
10561062
/**
10571063
* The field options.
10581064
*/
@@ -1081,6 +1087,8 @@ export class FieldApi<
10811087
TFormOnServer,
10821088
TParentSubmitMeta
10831089
> = {} as any
1090+
1091+
baseStore: Store<FieldBaseState<TParentData, TName>>
10841092
/**
10851093
* The field state store.
10861094
*/
@@ -1152,15 +1160,17 @@ export class FieldApi<
11521160
>,
11531161
) {
11541162
this.form = opts.form as never
1155-
this.name = opts.name as never
1163+
this.baseStore = new Store({
1164+
name: opts.name,
1165+
})
11561166
this.timeoutIds = {
11571167
validations: {} as Record<ValidationCause, never>,
11581168
listeners: {} as Record<ListenerCause, never>,
11591169
formListeners: {} as Record<ListenerCause, never>,
11601170
}
11611171

11621172
this.store = new Derived({
1163-
deps: [this.form.store],
1173+
deps: [this.baseStore, this.form.store],
11641174
fn: () => {
11651175
const value = this.form.getFieldValue(this.name)
11661176
const meta = this.form.getFieldMeta(this.name) ?? {
@@ -1312,7 +1322,9 @@ export class FieldApi<
13121322
this.options = opts as never
13131323

13141324
const nameHasChanged = this.name !== opts.name
1315-
this.name = opts.name
1325+
if (nameHasChanged) {
1326+
this.baseStore.setState((prev) => ({ ...prev, name: opts.name }))
1327+
}
13161328

13171329
// Default Value
13181330
if ((this.state.value as unknown) === undefined) {

packages/react-form/src/useField.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ export function useField<
219219
return extendedApi
220220
})
221221

222+
const nameHasChanged = fieldApi.name !== opts.name
223+
if (nameHasChanged) {
224+
fieldApi.baseStore.setState((prev) => ({ ...prev, name: opts.name }))
225+
}
226+
222227
useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi])
223228

224229
/**

packages/react-form/tests/useForm.test.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,4 +896,48 @@ describe('useForm', () => {
896896
await user.click(target)
897897
expect(result).toHaveTextContent('1')
898898
})
899+
900+
it('should allow custom component keys for arrays', async () => {
901+
function Comp() {
902+
const form = useForm({
903+
defaultValues: {
904+
foo: [
905+
{ name: 'nameA', id: 'a' },
906+
{ name: 'nameB', id: 'b' },
907+
{ name: 'nameC', id: 'c' },
908+
],
909+
},
910+
})
911+
912+
return (
913+
<>
914+
<form.Field name="foo" mode="array">
915+
{(arrayField) =>
916+
arrayField.state.value.map((row, i) => (
917+
<form.Field key={row.id} name={`foo[${i}].name`}>
918+
{(field) => {
919+
expect(field.name).toBe(`foo[${i}].name`)
920+
expect(field.state.value).not.toBeUndefined()
921+
return null
922+
}}
923+
</form.Field>
924+
))
925+
}
926+
</form.Field>
927+
<button
928+
type="button"
929+
onClick={() => form.removeFieldValue('foo', 1)}
930+
data-testid="removeField"
931+
>
932+
Remove
933+
</button>
934+
</>
935+
)
936+
}
937+
938+
const { getByTestId } = render(<Comp />)
939+
940+
const target = getByTestId('removeField')
941+
await user.click(target)
942+
})
899943
})

0 commit comments

Comments
 (0)