[react-form] Dynamic list addition/removal does not change the dirty state of the form
See original GitHub issueOverview
When combining useDynamicList
and useForm
, I would expect that calling addItem
or removeItem
for the dynamic list would result in the form being marked as dirty. Currently, it is only marked dirty if the values within the form fields have been edited.
The linked CodeSandbox from the documentation exhibits this behaviour and would be a good reference: https://codesandbox.io/s/hungry-rubin-exrkz?hidenavigation=1&theme=dark&file=/src/App.tsx:939-943
Load the form in the sandbox and then click the “Remove” button to remove the only card entry in the list. The list is now empty and I would expect the “Save” button to be available (to update the form to no longer have any cards associated). The actual behaviour is that “Save” is still disabled, so there isn’t a built-in way to solve this using the dirty
state.
Potential solution
To update the dirty
state of the form when these changes occur seems like it might be a little tricky, since it only accepts the fields
value at the moment, and doesn’t have any idea about the addItem
or removeItem
that are returned by useDynamicList
.
- Right now
fields
is aFieldDictionary<Item>[]
type, but it could be modified to an object type that extends the array type and also exposes adirty
field that could be set whenaddItem
orremoveItem
are invoked. - Alternatively, the
useDynamicList
result could also return adirty
property of its own that could be checked in addition to thedirty
property returned by theuseForm
. - Alternatively,
useForm
could accept a new argument like “wrap” that would take an object of name->function and then return a wrapped version of each of them, and internally would set thedirty
flag if any of those methods are called. This seems like it might be a bit painful to type, but from a developer flexibility standpoint I kinda like it.
Current workaround
Currently to workaround this, I have to keep some additional state in my component that manually wraps addItem
and removeItem
and keeps state on whether or not they have been called. Looks like this:
import {useState} from 'react';
import {useForm, useDynamicList} from '@shopify/react-form';
function Component() {
const [listDirty, setListDirty] = useState(false);
const {fields, addItem, removeItem} = useDynamicList(
[{name: 'Ryan'}],
() => ({name: ''})
);
const {dirty} = useForm({
fields: {fields},
onSubmit: async () => {}
});
const add = () => {
addItem();
setListDirty(true);
};
const remove = (index: number) => {
removeItem(index);
setListDirty();
};
if (dirty || listDirty) {
...
} else {
...
}
}
Consuming repo
Issue Analytics
- State:
- Created 3 years ago
- Reactions:2
- Comments:7 (6 by maintainers)
@ryanwilsonperkin and @mahmoudmoravej
We recently patched this in this PR . There’s also some new documentation on initializing the dynamic list here