Rohan Agarwal
Rohan Agarwal

Reputation: 2609

Optimize Repeated (Same) API Calls - React

Scenario -

Suppose, there is an API which gives a list of books.

[ { id:1,
name: "A",
author: "https://author/1"
},
{ id:2,
name: "B",
author: "https://author/10"
},
{ id:3,
name: "A",
author: "https://author/3"
},
{ id:4,
name: "A",
author: "https://author/1"
}
...
]

Now, I need to call the author API to get the author details, but I need to avoid calling those APIs which has already been called.

I tried doing it by keeping a state object and updating the object whenever a new api is called. If the API URL already has an entry in the object, that call is not repeated. However, I suspect because of async nature of setState, the update to the state Object are clubbed and in the subsequent iteration, when I check the object to find the previous entry, it doesn't reflect.

...
const[authorDetail, setAuthorDetail] = useState({});

useEffect(() => {

for(let i=0;i<books.length;i++)
{
  if(!authorDetail[books[i].author]) {
     // make API call to fetch author detail
     authorDetail[books[i].author] = "called"
     setState({...authorDetail});
}
});

How can I optimise the API call for this case. For example, if I have 7 Harry Potter books, I would like to make only one call to fetch J.K. Rowling's data.

Upvotes: 0

Views: 87

Answers (1)

Jeremy Klukan
Jeremy Klukan

Reputation: 238

I believe the problem here is that your effect is maintaining a reference to the old state object. I think the easiest way to solve it will be by using a ref object.

const authorDetail = useRef({});

useEffect(() => {
  for (let i = 0;i < books.length; i++) {
    if (!authorDetail.current[books[i].author]) {
      // make API call to fetch author detail
      authorDetail.current[books[i].author] = "called"
    }
  }
}, [books]); // note the dependencies here!

books is a dependency for the effect, but you could also provide empty square brackets ([]) which will force it to only run when the component mounts.

Upvotes: 1

Related Questions