Skip to content
This repository was archived by the owner on Jul 27, 2022. It is now read-only.

Commit 22f241e

Browse files
committed
fix(useFieldArray): nested field array not working
1 parent e3eb173 commit 22f241e

File tree

5 files changed

+108
-35
lines changed

5 files changed

+108
-35
lines changed

.changeset/six-cherries-boil.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-cool-form": patch
3+
---
4+
5+
fix(useFieldArray): nested field array not working

app/src/Playground/index.tsx

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,92 @@
11
/* eslint-disable no-console */
22

3-
import { useForm } from "react-cool-form";
3+
import { useForm, useFieldArray } from "react-cool-form";
44

55
export default () => {
6-
const { form, runValidation } = useForm({
7-
// validate: () => ({ foo: "Required" }),
8-
focusOnError: ["foo"],
6+
const { form } = useForm({
7+
defaultValues: {
8+
foo: [
9+
{
10+
name: "Iron Man",
11+
arr: [{ name: "iron arr.0" }, { name: "iron arr.1" }],
12+
},
13+
],
14+
},
15+
onSubmit: (values) => alert(JSON.stringify(values, undefined, 2)),
916
});
17+
const [fields, { push, insert, remove }] = useFieldArray("foo");
1018

1119
return (
12-
<>
13-
<form ref={form} noValidate>
14-
<input name="foo" required />
15-
<input name="bar" required />
16-
{/* <input type="submit" /> */}
17-
</form>
18-
<button type="button" onClick={() => runValidation(["bar"])}>
19-
Validate
20-
</button>
21-
</>
20+
<form ref={form}>
21+
<table>
22+
<thead>
23+
<tr>
24+
<th>Name</th>
25+
<th>Arr</th>
26+
<th>Actions</th>
27+
</tr>
28+
</thead>
29+
<tbody>
30+
{fields.map((fieldName, index) => (
31+
<tr key={fieldName}>
32+
<td>
33+
<input name={`${fieldName}.name`} />
34+
</td>
35+
<td>
36+
<Arr field={fieldName} />
37+
</td>
38+
<td>
39+
<button type="button" onClick={() => remove(index)}>
40+
REMOVE
41+
</button>
42+
</td>
43+
</tr>
44+
))}
45+
</tbody>
46+
</table>
47+
<div>
48+
<button
49+
type="button"
50+
onClick={() => {
51+
push({ name: "Loki", arr: [{ name: "Your Savior Is Here" }] });
52+
}}
53+
>
54+
PUSH
55+
</button>
56+
<button
57+
type="button"
58+
onClick={() =>
59+
insert(0, {
60+
name: "Spider Man",
61+
arr: [{ name: "Your Friendly Neighborhood Spider-Man" }],
62+
})
63+
}
64+
>
65+
INSERT
66+
</button>
67+
</div>
68+
<input type="submit" />
69+
<input type="reset" />
70+
</form>
2271
);
2372
};
73+
74+
function Arr({ field }: any) {
75+
const [fields, { push }] = useFieldArray(`${field}.arr`);
76+
77+
return (
78+
<div>
79+
{fields.map((fieldName) => (
80+
<input
81+
key={fieldName}
82+
style={{ height: "20px", width: "100px" }}
83+
type="text"
84+
name={`${fieldName}.name`}
85+
/>
86+
))}
87+
<button type="button" onClick={() => push({ name: "xxx" })}>
88+
inner push
89+
</button>
90+
</div>
91+
);
92+
}

src/types/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export type Fields = Map<
9292

9393
export type Parsers = ObjMap<Omit<FieldOptions, "validate">>;
9494

95-
export type FieldArray = ObjMap<{ fields: ObjMap; reset: () => void }>;
95+
export type FieldArray = ObjMap<{ fields: ObjMap; update: () => void }>;
9696

9797
interface EventOptions<V> {
9898
removeField: RemoveField;

src/useFieldArray.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ export default <T = any, V extends FormValues = FormValues>(
6666
const [fields, setFields] = useState<string[]>(getFields(true));
6767

6868
const updateFields = useCallback(() => {
69-
setFields(getFields());
70-
setNodesOrValues(getState("values"), {
71-
shouldSetValues: false,
72-
fields: Object.keys(fieldArrayRef.current[name].fields),
73-
});
69+
if (fieldArrayRef.current[name]) {
70+
setFields(getFields());
71+
setNodesOrValues(getState("values"), {
72+
shouldSetValues: false,
73+
fields: Object.keys(fieldArrayRef.current[name].fields),
74+
});
75+
}
7476
}, [fieldArrayRef, getFields, getState, name, setNodesOrValues]);
7577

7678
useEffect(() => {
@@ -83,14 +85,14 @@ export default <T = any, V extends FormValues = FormValues>(
8385
}
8486

8587
return () => {
86-
if (shouldRemoveField(name)) removeField(name);
88+
if (shouldRemoveField(name)) removeField(name, ["defaultValue"]);
8789
};
8890
// eslint-disable-next-line react-hooks/exhaustive-deps
8991
}, []);
9092

9193
if (!fieldArrayRef.current[name])
9294
fieldArrayRef.current[name] = {
93-
reset: updateFields,
95+
update: updateFields,
9496
fields: {},
9597
};
9698
if (validate) fieldValidatorsRef.current[name] = validate;
@@ -106,8 +108,8 @@ export default <T = any, V extends FormValues = FormValues>(
106108
let state = getState();
107109

108110
(["values", "touched", "errors", "dirty"] as Keys[]).forEach((key) => {
109-
const value = state[key][name];
110-
const fieldsLength = state.values[name]?.length;
111+
const value = get(state[key], name);
112+
const fieldsLength = get(state.values, name)?.length;
111113

112114
if (
113115
key === "values" ||
@@ -117,15 +119,12 @@ export default <T = any, V extends FormValues = FormValues>(
117119
)
118120
state = set(
119121
state,
120-
key,
121-
{
122-
...state[key],
123-
[name]: handler(
124-
Array.isArray(value) ? [...value] : [],
125-
key,
126-
fieldsLength ? fieldsLength - 1 : 0
127-
),
128-
},
122+
`${key}.${name}`,
123+
handler(
124+
Array.isArray(value) ? [...value] : [],
125+
key,
126+
fieldsLength ? fieldsLength - 1 : 0
127+
),
129128
true
130129
);
131130
});

src/useForm.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ export default <V extends FormValues = FormValues>({
704704
setNodeValue(name, value);
705705

706706
isFieldArray(fieldArrayRef.current, name, (key) =>
707-
fieldArrayRef.current[key].reset()
707+
fieldArrayRef.current[key].update()
708708
);
709709

710710
if (shouldTouched) setTouched(name, true, { shouldValidate: false });
@@ -774,7 +774,7 @@ export default <V extends FormValues = FormValues>({
774774
setStateRef("", state);
775775
onResetRef.current(state.values, getOptions(), e);
776776

777-
Object.values(fieldArrayRef.current).forEach((field) => field.reset());
777+
Object.values(fieldArrayRef.current).forEach((field) => field.update());
778778
},
779779
[getOptions, onResetRef, setNodesOrValues, setStateRef, stateRef]
780780
);

0 commit comments

Comments
 (0)