1

Code :

enter image description here

Result : Not have data in state

enter image description here
help me pls , thanks!

sir air
  • 77
  • 1
  • 1
  • 6

4 Answers4

5

setState is asynchronous that's why you are seeing books as empty array. Here is a quote from the React docs:

The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.

One thing you may be doing wrong is in your useEffect callback. If your effect returns a function, React will run it when it is time to clean up. And you don't want the setState functions in fetchData to be invoked during clean up as the component will probably be unmounted.

If you just want the fetchData to only run once after the component mounts, here is a possible solution:

useEffect(() => {
  // put the fetchData inside the effect
  async function fetchData() {
    setLoading(true);
    const name = await getNameGroup();
    const tmp = await getAll(name);
    console.log(tmp);
    setBooks(tmp);
    console.log(books); // may not be the same as tmp, but you will see the updated state in the next render
    setLoading(false);
  }
  fetchData();
},[]}

You should read more about useEffect hook in the React docs.

hangindev.com
  • 4,573
  • 12
  • 28
2

It's a stale closure problem.

Your useEffect where the fetchData is being called, has an empty dependency array. Within the fetchData function, which is inside useEffect, you are trying to print books which one first load, was initialized with an empty array.

All hooks hold the same reference to the variables with which they were initialized, till the dependencies change. To get an updated state, they depend on the dependency array. Since your dependency array doesn't specify books, it won't refresh the reference of books in your fetchData function either. Read more about the stale closure problem here

That's why your books variable is showing stale data.

export default function() {
    // fetch data here
    // runs only once because of empty dependency array
    useEffect(() => { 
      let isCancelled = false

       // define the fetchData inside the `useEffect` so that 
       // you can detect if the component has been unmounted      
       // using `isCancelled`
       const fetchData = async () => {
          const tmp = await getAll()

          // only update state if component isn't unmounted
          // if you try to update state on an unmounted component,
          // React will throw an error
          if (!isCancelled) {
             setIsLoading(false)
             setBooks(tmp)
          }
       }

       if (!isCancelled) {
         setIsLoading(true)
         fetchData()
       } 

       // cleanup
       return () => {
         isCancelled = true
       }
    }, [])

}
iamaatoh
  • 758
  • 5
  • 12
1
const [dataArray, setDataArray] = useState([]);

async function fetchData() {
    try {
        setIsLoading(true);
        const response = await getNameGroup();
        setDataArray(response);
    } catch(error) {
       // handle error
    } finally {
       setIsLoading(false);
    }
}
RMCS
  • 383
  • 3
  • 17
0

This is an example code that is working and you can apply:

const [data, setData] = useState([]); 
const [hasError, setErrors] = useState(false);

async function fetchData() {
const LibraryQuery = JSON.stringify({query: `query { species { id name description } }`});
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
const res = await fetch('http://localhost:3000/graphql',{
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': token
    },
    body: LibraryQuery
});
res
    .json()
    .then(res => setData(res.data))
    .catch(err => setErrors(err));
}

useEffect(() => {
  fetchData();
}, []);
Matinger
  • 1
  • 2