useFieldArray clears input values when element is removed
See original GitHub issueDescribe the bug I use useFieldArray to render a set of inputs that are based on a “map-object”. This object describes how the inputs should be layouted, which inputs should be rendered, which of them are required and so on:
const contentConfig = {
contentMap: [
{
key: "address",
value: "Address",
fields: [
[
{
key: "street",
value: "Street",
field: {
type: "text",
options: null
},
isRequired: null,
width: 6
}
],
[
{
key: "zip_code",
value: "ZIP",
field: {
type: "text",
options: null
},
isRequired: null,
width: 6
}
],
[
{
key: "label",
value: "Label",
field: {
type: "freeSolo",
options: ["Work", "Private", "Other"]
},
isRequired: null,
width: 12
}
]
]
}
]
};
My FieldArray component renders the inputs for each Element based on this map …
const FieldArray = ({ formMethods, name, arrayMap, ...rest }) => {
const { fields, append, remove } = useFieldArray({
control: formMethods.control,
name
});
const handleAddElement = () => {
append();
};
const handleDeleteElement = index => {
remove(index);
};
return (
<Fragment>
{fields.map((field, index) => {
const fieldName = `${name}[${index}]`;
return (
<Grid
container
spacing={1}
key={field.id}
style={{ marginBottom: "3rem" }}
>
<Grid item container spacing={2} xs={6}>
{arrayMap.map(row => {
return row.map(element => {
const newElem = { ...element };
newElem.key = `${fieldName}.${element.key}`;
newElem.value = `${element.value}`;
const renderedInput = getInputElement(
newElem,
formMethods,
rest
);
return (
<Grid
item
xs={element.width}
zeroMinWidth
key={newElem.key}
>
{renderedInput}
</Grid>
);
});
})}
</Grid>
<Grid xs={2} item zeroMinWidth>
<IconButton onClick={() => handleDeleteElement(index)}>
<DeleteIcon />
</IconButton>
</Grid>
</Grid>
);
})}
<Button onClick={handleAddElement} color="primary">
Add
</Button>
</Fragment>
);
};
… and returns either CustomInput or CustomFreeSolo:
const CustomInput = ({
name,
label,
isRequired,
register,
errors,
type,
...rest
}) => {
return (
<TextField
{...rest}
name={name}
required={Boolean(isRequired?.required)}
id={name}
type={type}
label={label}
inputRef={register(isRequired)}
/>
);
};
const useDefaultValue = (getValues, name) => {
const value = getValues(name);
return value ? value : "";
};
const CustomFreeSolo = ({
name,
label,
options,
autoComplete,
isRequired,
getValues,
type,
control,
selectOnFocus,
openOnFocus,
...rest
}) => {
const defaultValue = useDefaultValue(getValues, name);
const handleChange = (_, newValue) => {
return newValue;
};
return (
<Controller
name={name}
rules={isRequired}
control={control}
defaultValue={defaultValue}
onChange={([_, data]) => handleChange(_, data)}
as={
<Autocomplete
id={name}
freeSolo
options={options}
autoSelect
includeInputInList
openOnFocus={openOnFocus}
selectOnFocus={selectOnFocus}
autoComplete={autoComplete}
fullWidth={rest.fullWidth}
renderInput={params => {
return (
<TextField
{...params}
{...rest}
required={Boolean(isRequired?.required)}
label={label}
type={type}
/>
);
}}
/>
}
/>
);
};
const getInputElement = (element, formMethods, rest) => {
const { register, control, errors, getValues } = formMethods;
const {
key: name,
value: label,
field: { type, options },
isRequired
} = element;
switch (type) {
case "text":
return (
<CustomInput
{...{
name,
label,
isRequired,
register,
errors,
type
}}
{...rest}
/>
);
case "freeSolo":
return (
<CustomFreeSolo
{...{
name,
label,
isRequired,
control,
errors,
type,
options,
getValues
}}
{...rest}
/>
);
case "id":
return <input ref={register(isRequired)} name={name} hidden />;
default:
return null;
}
};
Now when I want to remove an element, all the elements that come after the removed one are either cleared or set to the default values entered in useForm.
To Reproduce
- Go to sandbox link and remove an element
Codesandbox link (Required) https://codesandbox.io/s/react-hook-form-fieldarray-bug-ti0td?file=/src/App.js
Expected behavior The fields should not be cleared after deleting an element.
Desktop (please complete the following information):
- OS: Win 10
- Browser opera, chrome
- Version latest
Issue Analytics
- State:
- Created 3 years ago
- Comments:14 (6 by maintainers)
Sometimes the solution is very simple:
I used the index of the last
.map
method as key for myGrid item
and now everything works fine:Updated Sandbox: https://codesandbox.io/s/react-hook-form-fieldarray-bug-53279?file=/src/FieldArray.js
OK, thanks I’ll try it out