Search code examples
reactjsuse-effect

Fetch runs double with old and updated value


I have a fetch function as a component:

export const FetchBooksBySubject = (selectedValue) => {
    const options = {
      method: `GET`,
    };
    return fetch(`${server}/books?subjects_like=${selectedValue}`, options)
    .then((response) => {
      if(response.ok){
        return response.json()
      }
        throw new Error('Api is not available') 
      })
    .catch(error => {
      console.error('Error fetching data: ', error)
    })
}

This function I use in my App.js, where the idea is, to run fetch every time, the value gets updated:

useEffect(() => {
   if(selectedValue) {FetchBooksBySubject(selectedValue).then(data => setBookList(data))};
  }, [selectedValue])

   
  const handleChange = e => {
    setSelectedValue(e);
    FetchBooksBySubject(selectedValue);
    
  };

So it works, but it runs a doble request basically when I set the new value. Firts is for the value before the update and second for the updated value. Why? And is there any chance to run it only for the updated value?


Solution

  • First, FetchBooksBySubject is not a valid function component. Component should return React element.

    const element = <h1>Hello, world</h1>;
    

    FetchBooksBySubject is just a function returns a Promise, so you should rename it like fetchBooksBySubject.

    Second, it is natural that your FetchBooksBySubject runs twice. The first time is when the selectedValue changes. Check out official document about useEffect. When you provide some value in your dependency array, the values's change will trigger useEffect to run again.

    useEffect(() => {
       if(selectedValue) {FetchBooksBySubject(selectedValue).then(data => setBookList(data))};
    }, [selectedValue])
    

    The second time when fetching is called is after setSelectedValue, you are calling fetch function manually. So delete it if you don't need it.

    const handleChange = e => {
        setSelectedValue(e);
        FetchBooksBySubject(selectedValue); // function called manually
    };