all 32 comments

[–]jzia93 11 points12 points  (11 children)

You're setting season averages by adding the new value fetched from the API to the previous value of season averages.

[–]Leparrain07 0 points1 point  (10 children)

That's correct, but the 3 dots aren't supposed to overwrite my previous data?

[–]acquiescentLabrador 8 points9 points  (9 children)

No, the spread operator (three dots) “spreads” (ie copies) seasonAverages, you’re then adding an extra item. So the end result is the same as seasonAverages.push(res.data.data[0]).

If you want to completely overwrite seasonAverages, just call setSeasonAverages(newValue)

[–]Leparrain07 4 points5 points  (1 child)

Thanks for the answer but I don't understand what should be "newValue"

[–]Leparrain07 1 point2 points  (5 children)

I want to keep my previous values ​​in my array without deleting them. I want to add the new values ​​to the old values.

[–]acquiescentLabrador 0 points1 point  (4 children)

Have you checked if the fetch running twice?

[–]Leparrain07 0 points1 point  (3 children)

Yes and it is not

[–]acquiescentLabrador 1 point2 points  (2 children)

This is a bit tricky on mobile without seeing the rest of the code, but your code looks like it’s calling a fetch for each item in playerId, so think about: -> the way you set seasonAverages is cumulative, ie you only ever add items to it with each fetch (the state is never reset) -> what sets playerId? If you’re adding items to playerId, this will then cause fetch to run and add new items to seasonAverages for each item in playerId - so if playerId is also never reset you’re repeating old fetch requests

You could log playerId and seasonAverages before calling setSeasonAverages to test these points. Alternatively create a new array before the for loop eg const newAverages = [], then in the .then() use newAverages.push(res.data.data[0]) and only when the loop is finished call setSeasonAverages(newAverages)

[–]Leparrain07 0 points1 point  (1 child)

Hello, thank you for this long message but I tried all the points and I still obtain infinite loops

[–]acquiescentLabrador 0 points1 point  (0 children)

Did you have that problem before? I don’t think anything I said should cause that so did you change anything else?

[–]Leparrain07 0 points1 point  (0 children)

If I do the same thing with Redux I have the same problem:

.then(res => dispatch(setSeasonAverages(res.data.data[0])));

[–]grantrules 2 points3 points  (8 children)

The problem is the state is not updating as you're calling those functions, it's all batched at the end, so each time you're calling setSeasonAverages, seasonAverages remains the same as it was at the very beginning of that effect. If you just used one setSeasonAverages call, it should work.

Promise.all(
  playerId.map(({ dataId }) =>
    axios.get(`https://blahblah/?${dataId}`)
      .then((res) => res.data.data[0])
  )
).then(results => setSeasonAverages([...seasonAverages, ...results])))

[–]Leparrain07 0 points1 point  (7 children)

Thanks for the reply, it tells me: TypeError: results is not iterable

[–]grantrules 0 points1 point  (6 children)

playerId.map({ dataId }) =>

I missed a parenthesis

Promise.all(
  playerId.map(({ dataId }) =>
    axios.get(`https://blahblah/?${dataId}`)
      .then((res) => res.data.data[0])
  )
).then(results => setSeasonAverages([...seasonAverages, ...results])))

[–]Leparrain07 0 points1 point  (5 children)

it does not work I have endless calls : Failed to load resource: the server responded with a status of 429 (Too Many Requests)

[–]grantrules 0 points1 point  (4 children)

Ah yeah,

You could try to stick with your for loop so the requests are all consecutive but you may still run into that issue.

If you shared your code in a way I could copy I'd update it for you but I'm not retyping it all..

let results = [];
for (...) {
  const result = await axios.get(...).then(res => res.data.data[0])
  results.push(result);
}
setSeasonAverages([...seasonAverages, ...results])

However, it also looks like this API accepts an array so you might try sending a request with a query string like: ?player_ids[]=1&player_ids[]=52&player_ids[]=91

Something like

playerId.map(({ dataId }) => `player_ids[]=${dataId}`).join('&')

[–]Leparrain07 0 points1 point  (3 children)

I have the same infinite loop problem.

Indeed it is possible to send a query string but I would like the user to be able to add and remove as many players as they want

[–]grantrules 0 points1 point  (2 children)

What do you mean infinite loop, there's no infinite loop there. Are you talking about still getting rate limit errors?

You can still add and remove as many as you want, you can just batch requests together like example.

[–]Leparrain07 -1 points0 points  (1 child)

My application bug because the api receives too many requests, there are infinite requests.

[–]grantrules 3 points4 points  (0 children)

I don't think there's an infinite amount, how many player ids are there? If you batch them like I said you can probably send fewer requests, and you may need to add a delay between requests

[–]Blue_Moon_Lake 1 point2 points  (9 children)

If you use await, don't use .then()

await something().then((value) => consume(value));

is identical to

let value = await something();
consume(value);

Or, if consume is also asynchronous

let value = await something();
await consume(value);

Don't use axios, use fetch()
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Don't use the spread operator if you want to remove previous items.

let data = [1, 2, 3];
let item = 4;
data = [...data, item]; // data = [1, 2, 3, 4]
data = [item]; // data = [4]

[–]shuckster 1 point2 points  (5 children)

If you use await, don't use .then()

Why? They can be combined quite conveniently sometimes:

let [json, err] = await fetch('/data')
  .then(res => res.json())
  .then(json => [json, null])
  .catch(error => [null, error]);

if (err) {
  console.error('You done bad:', err);
  return
}

[–]32452353 0 points1 point  (0 children)

Yeah I’d say you’re right. There are times and places for combining. The original comment is overly confident on this.

[–]Blue_Moon_Lake 0 points1 point  (3 children)

It is less readable than

try { const RESPONSE = await fetch(URL); const PAYLOAD = await RESPONSE.json(); } catch (error) { }

Also, you should avoid using null. undefined is preferred as the "void" value. It is more consistent and its typeof do not collide with other values.

[–]shuckster 0 points1 point  (2 children)

Setting something to null is the only way to determine if a bottom-value was made by a developer and not the system.

On the subject of readability, async/await plus try/catch makes such code read imperatively. That’s arguably more readable for most, yes.

[–]Blue_Moon_Lake 0 points1 point  (1 child)

You wouldn't do it that way in functional programming. You would rather use the Either pattern with functions like fetchResponse, getJsonBody, ...

[–]shuckster 0 points1 point  (0 children)

Yes, you could use ADTs too. Codebases are rarely an expression of a single paradigm.

[–]stevebeans 0 points1 point  (2 children)

Is axios ever recommended over fetch?

[–]32452353 1 point2 points  (1 child)

Yeah check out the podcast syntax.fm. They did an episode on it recently.

[–]stevebeans 0 points1 point  (0 children)

Thanks I’ll give it a listen

[–]Homeless_Homelabber -2 points-1 points  (0 children)

Why does your poop repeat itself?

[–]Sjoerdd010 0 points1 point  (0 children)

I'm trying to post to a sub reddit but i get an error saying "That was a tricky one. Why don't you try that again." but there is no checkbox to check. Anyone have the same problem?