9

I have a component in React in need of an array of users. I'm able to fetch one single user at a time with useUwr like so:

export function Hello(id: number) {
  const { data } = useSWR('/api/user/{id}', fetcher)

  return <div>hello {data.name}!</div>
}

What I need now is an array of users, so basically:

var users = [];  
for(var i = 0; i < 100; i++) {
   const { data } = useSWR('/api/user/{i}', fetcher); 
   users.push(data);
}

Issue with this approach is Error: Rendered more hooks than during the previous render.

Was thinking that there must be a smarter way to fetch the data of 100 users. Thanks for any suggestion.

DLO
  • 914
  • 1
  • 13
  • 30
  • React hooks can only be declared in the top level. You cannot define inside the for loop. To fix your issue you can have a separate API to get a list of users like /api/user/getUsers – Amila Senadheera Nov 04 '21 at 09:49

3 Answers3

6
function multiFetcher(...urls) {
  return Promise.all(urls.map(url => fetcher(url))
}

const { data: [data1, data2, data3] } = useSWR([url1, url2, url3], multiFetcher)
Callam
  • 949
  • 1
  • 14
  • 22
  • Please read [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). While this code block may answer the OP's question, this answer would be much more useful if you explain how this code is different from the code in the question, what you've changed, why you've changed it and why that solves the problem without introducing others. - [From Review](https://stackoverflow.com/review/low-quality-posts/32238228) – Saeed Zhiany Jul 20 '22 at 03:33
4

Try this:

function arrayFetcher(...urlArr) {
  const f = (u) => fetch(u).then((r) => r.json());
  return Promise.all(urlArr.map(f));
}

export function Hello(id: number) {
  let urlArray = [];
  for(let i = 0; i < 100; i++) {
    urlArray.push(`/api/user/${i}`);
  }
  const { data } = useSWR(urlArray, arrayFetcher);

  return (
    <ul>{data && data.map(x => <li key={x.name}>x.name</li>)}</ul>
  )
}
santon
  • 4,395
  • 1
  • 24
  • 43
SoGoddamnUgly
  • 706
  • 4
  • 9
  • From what I've tried, this doesn't work the way that it's assumed it would. While `urlArray` goes in as an array, `urlArr` is coming out as the first item of the array. Line three then fails as .map only works on arrays when 'urlArr' isn't an array. This makes sense as the useSWR call takes an array for the purpose of multiple variables for the purpose of pagination. – Casey Gibson Jan 20 '22 at 04:52
  • 1
    @KcGibson You should the [rest paramater](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) on `urlArr`, i.e. `function arrayFetcher(...urlArr) { ... }` – juliomalves Feb 05 '22 at 01:25
  • 1
    For SWR version >= 2.0.0, urlArr shoud be an array instead of a spreading argument per [doc](https://swr.vercel.app/docs/arguments#multiple-arguments) – Xhua Mar 07 '23 at 16:04
-1

add urlArray in array

const { data } = useSWR([urlArray], arrayFetcher);
  • Please read [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) so you can share what is `arrayFetcher` or how the user can use `data` You just put one line of code and it's not a proper way to write a proper answer. – Reza Majidi Jun 14 '23 at 12:25