swr
swr copied to clipboard
Local mutations should work even when not fetching
Bug report
Description / Observed Behavior
I have a UserDialog
component that can either create a new user or edit an existing user. When creating a new user, I still want to useSWR
to manage the component state like so:
import useSWR from 'swr';
export default function CreateUserDialog({
id,
onClosed,
initialData = (new User().toJSON()),
}: CreateUserDialogProps): JSX.Element {
const { data: user, mutate } = useSWR<UserJSON>(id ? `/api/users/${id}` : null, { initialData });
return (
<Dialog open onClosed={onClosed} className={styles.dialog}>
<form className={styles.form}>
<Inputs value={user as UserJSON} onChange={(updated: UserJSON) => {
// Locally update the SWR data but don't actually create or fetch the data from the remote
// until after the user clicks the "create user" button.
void mutate(updated, false);
}} />
</form>
</Dialog>
);
}
This doesn't work, however, because I can't seem to locally mutate the SWR data when the hook wasn't given a key (i.e. when I tell the hook not to fetch yet). This makes sense because SWR doesn't have a key yet. But I should still be able to do this when using the bound mutate
callback.
Expected Behavior
Ideally, this should be able to work when using the bound mutate
callback (OFC it's not going to work when using the global callback because there isn't a key to reference).
The bound mutate is not a special function, only do this (data, shouldRevalidate) => mutate(key,data, shouldRevalidate)
and pass the key of the hook. The source of true of SWR is always the cache, not the internal state of the hook, that is why you can't do that.
I recommend you to create a key for the new user, something like "fake-user" and make your fetcher recognize it and return the new User().toJSON(). Once your component unmount remember to run cache.delete("current-user") so you don't keep the data between usages. Also you may want to disable all revalidations if there is no user.
According to docs it should be possible to update local state (stale data) until re-fetch is done... Even with the "bound" mutation function
By local it means the cached data (local is the browser, remote is the API), so you can call mutate(key, newData, false)
to mutate the cached data without a revalidation, but you need a key and if for some reason SWR decides to revalidate you will lose the non persisted changes.