Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: mutateTag #4070

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

feat: mutateTag #4070

wants to merge 1 commit into from

Conversation

koba04
Copy link
Collaborator

@koba04 koba04 commented Jan 16, 2025

Proposal for mutateTag Function

This is just a proposal, so it doesn't mean we have a consensus to spport this.

Overview

The mutateTag function proposes a straightforward method to mutate cached data by using tags. This feature allows developers to manage mutations more effectively, enhancing ease of use and flexibility. Below is an example of how this function can be utilized.

useSWR("/api/user/1", fetcher, { tags: ["user", "user1"] });
useSWR("/api/user/2", fetcher, { tags: ["user", "user2"] });

const getKey = (page) => `/api/users?page=${page + 1}`;
useSWRInfinite(getKey, fetcher, { tags: ["user"] });

// Mutate all cached data tagged as "user"
mutateTag("user");

Changes

add a new mutateTag function

import { mutateTag } from "swr";
// or
const { mutateTag } = useSWRConfig();

mutateTag has a similar interface, which looks like

mutateTag('tag', data, options)

add tag options to useSWR, useSWRInfinite

useSWR("/api/user", fetcher, { tag: ["user"] });
useSWRInfinite(getKey, fetcher, { tag: ["user"] });

Motivation

The mutateTag function enables cache mutation based on assigned tags. This approach offers several advantages over the existing "Mutate Multiple Items" method.

Simplicity

While a key filter function provides flexibility, it can become complex when keys are not organized. Developers often use URLs as keys, which can lead to cumbersome mutations. For instance:

const { mutate } = useSWRConfig();

useSWR("/api/user?...query", fetcher);
mutate((key) => typeof key === 'string' && key.startsWith('/api/user'), data);

This method is too low-level and relies on URLs that may not be the best abstraction for handling mutations.

With mutateTag, the process is streamlined:

const { mutateTag } = useSWRConfig();

useSWR("/api/user?...query", fetcher, { tag: ["user"] });
mutateTag("user");

Enhanced Support for useSWRInfinite

A long-standing challenge with SWR has been the limited ability to perform mutations for useSWRInfinite, which typically require bound mutate functions. The existing "Mutate Multiple Items" technique is insufficient because it depends on internal cache data tied to specific format keys. We can use an unstable API unstable_serialize to mutate the internal cache data but we want to shield developers from the complexities of these special keys, making "Mutate Multiple Items" less viable.

This also can't cover patterns like useSWRInfinite with filtering queries.

For example, we have multiple keys with useSWRInfinite, which has different filtering conditions, and then mutated a user of the list

  • /api/users?page=1&filter=admin
  • /api/users?page=2&filter=admin
  • /api/users?page=1&filter=none

In this case, it's impossible to mutate the cache data unless we iterate cache data directly. We can't use "Mutate Multiple Items" because it skips internal cache data for useSWRInfinite.

By utilizing mutateTag, developers can effectively mutate this cached data without needing to interact with any special format keys:

const { mutateTag } = useSWRConfig();

useSWRInfinite(getKey, fetcher, { tag: ["user"] });
mutateTag("user");

This will make mutations for useSWRInfinite drastically simple and safe.

What about useSWRSubscription?

This is a good point, Initially I considered supporting useSWRSubscription as well, but useSWRSubscription doesn't support mutate, so I didn't have confident to include useSWRSubscription.
(I could add it later if that makes sense)

Prior Art

This proposal draws inspiration from similar functionalities, such as revalidateTag in Next.js, which showcases the effectiveness of tag-based cache management.

@koba04 koba04 requested review from shuding and huozhi as code owners January 16, 2025 13:03
Copy link

codesandbox-ci bot commented Jan 16, 2025

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant