Home > database >  React State not Updating Immediately?
React State not Updating Immediately?

Time:10-30

I want to use the fctGtVal function whenever I click on the input. The searchMovsByG function will set the moviesId by the result and then it will display the result. But the useState set method not reflecting change immediately so the result is not what i want

Here is my code:



import React, { useEffect, useState } from "react";


function App() {

  const [searchG,setSearchG] = useState('');
  const [moviesId,setMoviesId] = useState([]);

  const searchMovsByG = async(searchG)=>{

    const response = await fetch(`https://moviesminidatabase.p.rapidapi.com/movie/byGen/${searchG}/?page_size=10`, {
        headers: {
          "X-Rapidapi-Key": "89c7f5afc0mshdc9500aabf8c53ap15f02ejsn0e2d634195f8"
        }
      })
    const data = await response.json();
      console.log("--------------------------");
            setMoviesId(data.results);
            console.log(moviesId);  
      console.log("--------------------------");

}  


const fctGtVal = (e)=>{
  setSearchG(e.target.value);
  searchMovsByG(searchG);
}



useEffect(()=>{
  searchMovsByG("Drama");
},[])





  return (
    <>
    <div className="App">
    <input value="Action" onClick={fctGtVal}/>
    <input value="Music" onClick={fctGtVal}/>
    <input value="Family" onClick={fctGtVal}/>


</div>







   
    </>
  );
}

export default App;

CodePudding user response:

That's how states work in react. You set them with the set-function, but the value is only updated after the rerender. Therefore searchMovsByG(searchG) gets called with an old value.

What you can do for example is (not a clean solution, just for understanding):

useEffect(()=>{
  searchMovsByG(searchG);
},[searchG])

With this, every time searchG changes, the API gets called with the new value. Therefore in fctGtVal you just need to have setSearchG(e.target.value) an nothing more.

But a better solution would be, if you call searchMovsByG directly with the click on a button and the correct value:

const fctGtVal = (e)=>{
  setSearchG(e.target.value);
  searchMovsByG(e.target.value);
}

CodePudding user response:

You are right, React state is immutable and state changes are only reflected after a rerender, this is because each render creates a new closure which references the current value of your state.

What happens in function components is that every time that you call a state setter, the component function will be called again, but now the useState hook will return the updated value. If you are not used to react, this is something you will need to get used to.

More information about closures:

An alternative option, if you don't want your component to re-render every time your value changes is to use the useRef hook. It works differently, refs are mutable and they don't have setter functions. This is how it will look:

function App() {
  const moviesIdRef = useRef();

  const searchMovsByG = async(searchG)=>{
    const response = await fetch(`https://moviesminidatabase.p.rapidapi.com/movie/byGen/${searchG}/?page_size=10`, {
      headers: {
        "X-Rapidapi-Key": "89c7f5afc0mshdc9500aabf8c53ap15f02ejsn0e2d634195f8"
      }
    });

    const data = await response.json();
    moviesIdRef.current = data.results;

    console.log("--------------------------");
    console.log(moviesIdRef.current);  
    console.log("--------------------------");
  }
...
}

Note that the useRef example above will not cause a re-render to your component and will not be reflected without triggering a re-render another way.

Some More information about useRef:

  • Related