diff --git a/.changeset/six-cherries-boil.md b/.changeset/six-cherries-boil.md new file mode 100644 index 00000000..73b05f7d --- /dev/null +++ b/.changeset/six-cherries-boil.md @@ -0,0 +1,5 @@ +--- +"react-cool-form": patch +--- + +fix(useFieldArray): nested field array not working diff --git a/app/src/Playground/index.tsx b/app/src/Playground/index.tsx index ce93eb03..53d04332 100644 --- a/app/src/Playground/index.tsx +++ b/app/src/Playground/index.tsx @@ -1,23 +1,92 @@ /* eslint-disable no-console */ -import { useForm } from "react-cool-form"; +import { useForm, useFieldArray } from "react-cool-form"; export default () => { - const { form, runValidation } = useForm({ - // validate: () => ({ foo: "Required" }), - focusOnError: ["foo"], + const { form } = useForm({ + defaultValues: { + foo: [ + { + name: "Iron Man", + arr: [{ name: "iron arr.0" }, { name: "iron arr.1" }], + }, + ], + }, + onSubmit: (values) => alert(JSON.stringify(values, undefined, 2)), }); + const [fields, { push, insert, remove }] = useFieldArray("foo"); return ( - <> -
- - - {/* */} -
- - +
+ + + + + + + + + + {fields.map((fieldName, index) => ( + + + + + + ))} + +
NameArrActions
+ + + + + +
+
+ + +
+ + +
); }; + +function Arr({ field }: any) { + const [fields, { push }] = useFieldArray(`${field}.arr`); + + return ( +
+ {fields.map((fieldName) => ( + + ))} + +
+ ); +} diff --git a/src/types/index.ts b/src/types/index.ts index 14390f9f..e122f27f 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -92,7 +92,7 @@ export type Fields = Map< export type Parsers = ObjMap>; -export type FieldArray = ObjMap<{ fields: ObjMap; reset: () => void }>; +export type FieldArray = ObjMap<{ fields: ObjMap; update: () => void }>; interface EventOptions { removeField: RemoveField; diff --git a/src/useFieldArray.ts b/src/useFieldArray.ts index 6b2e3000..1cf95984 100644 --- a/src/useFieldArray.ts +++ b/src/useFieldArray.ts @@ -66,11 +66,13 @@ export default ( const [fields, setFields] = useState(getFields(true)); const updateFields = useCallback(() => { - setFields(getFields()); - setNodesOrValues(getState("values"), { - shouldSetValues: false, - fields: Object.keys(fieldArrayRef.current[name].fields), - }); + if (fieldArrayRef.current[name]) { + setFields(getFields()); + setNodesOrValues(getState("values"), { + shouldSetValues: false, + fields: Object.keys(fieldArrayRef.current[name].fields), + }); + } }, [fieldArrayRef, getFields, getState, name, setNodesOrValues]); useEffect(() => { @@ -83,14 +85,14 @@ export default ( } return () => { - if (shouldRemoveField(name)) removeField(name); + if (shouldRemoveField(name)) removeField(name, ["defaultValue"]); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); if (!fieldArrayRef.current[name]) fieldArrayRef.current[name] = { - reset: updateFields, + update: updateFields, fields: {}, }; if (validate) fieldValidatorsRef.current[name] = validate; @@ -106,8 +108,8 @@ export default ( let state = getState(); (["values", "touched", "errors", "dirty"] as Keys[]).forEach((key) => { - const value = state[key][name]; - const fieldsLength = state.values[name]?.length; + const value = get(state[key], name); + const fieldsLength = get(state.values, name)?.length; if ( key === "values" || @@ -117,15 +119,12 @@ export default ( ) state = set( state, - key, - { - ...state[key], - [name]: handler( - Array.isArray(value) ? [...value] : [], - key, - fieldsLength ? fieldsLength - 1 : 0 - ), - }, + `${key}.${name}`, + handler( + Array.isArray(value) ? [...value] : [], + key, + fieldsLength ? fieldsLength - 1 : 0 + ), true ); }); diff --git a/src/useForm.ts b/src/useForm.ts index b003ee65..9a3394e5 100644 --- a/src/useForm.ts +++ b/src/useForm.ts @@ -704,7 +704,7 @@ export default ({ setNodeValue(name, value); isFieldArray(fieldArrayRef.current, name, (key) => - fieldArrayRef.current[key].reset() + fieldArrayRef.current[key].update() ); if (shouldTouched) setTouched(name, true, { shouldValidate: false }); @@ -774,7 +774,7 @@ export default ({ setStateRef("", state); onResetRef.current(state.values, getOptions(), e); - Object.values(fieldArrayRef.current).forEach((field) => field.reset()); + Object.values(fieldArrayRef.current).forEach((field) => field.update()); }, [getOptions, onResetRef, setNodesOrValues, setStateRef, stateRef] );