Skip to content

Improving immediate mutate + later revalidation #157

@Daiz

Description

@Daiz

The documentation for mutate talks about local mutation for faster feedback, but the documented way to use it only mutates after a promise has resolved - in other words, not immediately.

As a result, I've found myself writing code in this kind of pattern:

mutate(path, { ...data, patch }, false); // mutate immediately, don't revalidate
await patchData(patch); // await the actual API call
trigger(path); // trigger revalidation afterwards

Technically, if patchData also returns the full new data, you could also do it like this:

mutate(path, { ...data, patch }, false); // mutate immediately locally, don't revalidate
mutate(path, patchData(patch), false); // update with API-backed result from patchData

Which is actually also present in the documentation. But it is kinda janky to need two subsequent mutate calls for this...

One backwards-compatible way to deal with this could be to extend mutate to accept options as the third parameter, and introduce initialData much like present in useSWR. Then you could do something like this:

// mutate immediately with `initialData`,
// then replace with result from patchData when it resolves
mutate(path, patchData(patch), { initialData: { ...data, patch }); 

In case the patchData function (or equivalent) doesn't return the full data, the third argument could also be augmented to accept a Promise, eg.

// wait until the Promise from patchData resolves before triggering revalidate
mutate(path, { ...data, patch }, patchData(patch))

I feel both these changes would make using mutate a lot more ergonomic overall.

In addition, I haven't checked the code to see how easy this would be to implemented, but another nice possibility would be to keep the local data (ie. non-promise second argument if third arg is a promise, anything in initialData) provided to mutate in some sort of "unverified cache", such that in case the provided promises throw, SWR could automatically roll the data back to "last known good value" (ie. the last real API response for that path).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions