7

I am using SWR to fetch data to populate a table with. I am using the following code:

const { data: items, error } = useSWR(fetchAllItems.name, fetchAllItems)

The fetcher function looks like this

async function fetchAllItems() {
  const response = await fetch('http://localhost:3000/items')
  const data = await response.json()
  return data
}

The table also has an options to add a new item. After creating the new item I call mutate to let SWR fetch the new data. While running this in development mode it all works great, however when using next start instead of next dev it won't fetch the data. In the networks tab it shows 0 requests, so it looks like the fetcher function is never called.

The server where the data is fetched from is running properly. I have tested this using postman and it returns all the items. It is also accessible from the next application, because creating a new item works fine.

EDIT: After some more debugging I have narrowed it down to the fact that SWR is never validating when using next start instead of next dev.

EDIT 2: A codesandbox with a minimal reproducible example can be found here https://codesandbox.io/s/elated-cherry-3ugqyi?file=/package.json . De codesandbox runs the program using npm run dev (which calls next dev) so everything works fine. However when running it with npm run build && npm run start useSWR no longer calls the fetcher function.

EDIT 3: I have resolved the issue, but don't understand how. I changed the fetcher function to the following:

function fetchAllItems() {
  return fetch('http://localhost:3000/items').then((res) => res.json())
}

The fetcher function is now no longer async, however it still returns a Promise (because fetch returns a Promise). If anyone could explain why this code behaves differently from the previous that would be great.

Danagon
  • 395
  • 5
  • 15
  • What is 'SERVER_URL' referencing? Your fetcher is supposed to accept a url argument that you use in fetch and that corresponds to the first argument to useSWR – deowk Mar 18 '22 at 13:55
  • The URL for this fetcher is fixed. I didn't want to reveal the domain name, so I replaced it with 'SERVER_URL'. I'll replace it with localhost to make it more clear, it is not relevant where the backend server is hosted – Danagon Mar 18 '22 at 14:07
  • It seems to be working... I just forked your sandbox and everything looks fine. I changed `"dev"` to `"next build && next start"` – dimiguel Mar 21 '22 at 23:19
  • There is literally no difference between your two functions – Phil Mar 22 '22 at 01:25
  • 1
    @Phil I thought the same, still one of them is working and the other isn't. And only when using next start instead of next dev. I think I am gonna make a proper reproducible example (not in a codesandbox) and test it on multiple devices/environments. And if the problem persist ask Vercel about it – Danagon Mar 22 '22 at 01:29

2 Answers2

7

Your fetcher function is fine as is. The issue occurs because in the production build fetchAllItems.name resolves to an empty string '', meaning useSWR will not call the fetcher function as the key param is a falsy value.

You have two options to solve the problem.

#1 Use hardcoded string as useSWR key

Simply use a string as the key parameter in the useSWR. I'd recommend this approach, as using fetchAllItems.name may not always return the expected value in production.

const { data: items, error } = useSWR('fetchAllItems', fetchAllItems)

#2 Use named function for fetchAllItems

Use the named function format for the fetchAllItems function, instead of an arrow function. This was probably what fixed the issue for you when you defined the new function without async/await.

export async function fetchAllItems() {
    const response = await fetch('http://localhost:3000/items')
    const data = await response.json()
    return data
}
juliomalves
  • 42,130
  • 20
  • 150
  • 146
0

Need to pass an arow function as fetcher that executes the fetchAllItems function:

const { data: items, error } = useSWR(fetchAllItems.name, () => fetchAllItems())
Behzad
  • 1,740
  • 1
  • 22
  • 49