
- 77
- 1
- 1
- 6
-
books default is [] . "const [books, setBooks] = useState([]);" – sir air Jun 12 '20 at 14:20
-
1What do you get if you `console.log(tmp)` in the function? – RMCS Jun 12 '20 at 14:27
-
Please copy and paste or type the actual code or message into the post directly next time. It helps others to help you. ;) – hangindev.com Jun 12 '20 at 14:44
4 Answers
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.

- 4,573
- 12
- 28
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 book
s 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
}
}, [])
}

- 758
- 5
- 12
const [dataArray, setDataArray] = useState([]);
async function fetchData() {
try {
setIsLoading(true);
const response = await getNameGroup();
setDataArray(response);
} catch(error) {
// handle error
} finally {
setIsLoading(false);
}
}

- 383
- 3
- 17
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();
}, []);

- 1
- 2