16

In my app every time the user creates a new album the post request response responds with a list of the updated list of albums.

To provide a better user experience, I wanted the user to see the new content in the app without having to refresh the page.

I'm aware of the existence of SWR's mutate, but so far, I couldn't make it work.

I tried to set a 1000ms refreshInterval in my hook, but I wanted to know how to do it by using the mutate. Here's what I tried:

SWR hook

const fetcher = async (url: string, param: string) => {
    const res = await fetch(url + param);
    
   return res.json();
};


const { data, error } = useSWR(
 ["/api/albums/list?id=", appUser.id],
  (url, params) => fetcher(url, params)
);

Inside the createAlbum function:

const data = await response.json();

mutate("/api/albums/list", data.newAlbums, false);

I would be happy to get some feedback.

Trevor Reid
  • 3,310
  • 4
  • 27
  • 46
gabriel_tiso
  • 1,007
  • 3
  • 11
  • 27

3 Answers3

42

Your code is almost correct, the issue lies in the fact that SWR internally hashes the keys used for queries/mutation. Therefore, the key used by the mutate function is simply not registered in the cache.

Using global mutate

To solve this problem using the mutate function exported directly by swr, it will suffice just to pass the same key to both useSWR and mutate.

mutate(["/api/albums/list?id=", appUser.id]);

This will invalidate the cache for the hashed key. The data retrieved from your original hook will go stale, and will therefore be fetched again.

Using bound mutate

Another option is to take advantage of the mutate function bound to swr's key.

const { data, error, mutate } = useSWR(
   ["/api/albums/list?id=", appUser.id],
   (url, params) => fetcher(url, params)
);

/*
 * Now you can just call `mutate()` without specifying `key` argument
 */

docs: https://github.com/vercel/swr#bound-mutate

Specifying a refresh interval

For completeness, as you said, one other option would be just to set the value of refreshInterval prop. Forcing a refetch when desired:

const { data, error } = useSWR(
   ["/api/albums/list?id=", appUser.id],
   (url, params) => fetcher(url, params),
   {
     refreshInterval: 1000, 
   }
);

lucagez
  • 536
  • 6
  • 4
  • Perfect answer, sufficed all my needs :) . One more thing, you can see that my fetcher has (url, params) as arguments. I wanted to pass an argument like so (...args), but I get a typescript error. You don't need to answer that, I already upvoted and accepted, but I wanted to know that, because I already made a question on that, but I wasn't able to get a response – gabriel_tiso Oct 07 '20 at 17:31
1

The reason your UI is not refreshing after the mutate is because the first argument passed into the mutate() and useSWR() don't match each other.

The first argument is essentially a unique key that SWR uses to associate the hook with the mutate. Update your mutate call to use the same key as the hook, and it should fix your problem.

mutate("/api/albums/list?id=", data.newAlbums, false);
Ro Milton
  • 2,281
  • 14
  • 9
0

you can do as follow

const { data, mutate, error } = useSWR(
 ["/api/albums/list?id=", appUser.id],
  (url, params) => fetcher(url, params)
);

to reload swr cache just call mutate(); .

This mutate refer to your album fetch call. Swr automatically refetch your data.

dna
  • 2,097
  • 1
  • 11
  • 35
  • `revalidate()` is the canonical call to refresh data. – AKX Oct 07 '20 at 16:56
  • i don't see any `revalidate()` function in `swr` https://github.com/vercel/swr#manually-revalidate. – dna Oct 07 '20 at 16:58
  • 1
    It's apparently undocumented, but it's there alright. https://github.com/vercel/swr/blob/651c368833164945a8ee5708eb3dd6091241f05b/src/types.ts#L80 – AKX Oct 07 '20 at 17:43