I am getting the content in an array and I can see the contents of the array on console.log.
However, the length is 0 and the contents cannot be retrieved with a map. Why is this?
const contents = [] as any[]
useEffect(() => {
for(const key of Object.keys(fruits)) {
contents[key as any] = {
...fruits[key as any],
...vegetables[key as any],
}
}
}, [fruits, vegetables, contents])
console.log('contents', contents)
console.log('contents length', contents.length)
You can try to have contents in the state instead of exposing it as a variable.
contents will be updated accordingly and correctly whenever fruits or vegetables get updated.
const [contents, setContents] = useState([])
useEffect(() => {
const updatedContents = [...contents]
for(const key of Object.keys(fruits)) {
updatedContents[key as any] = {
...fruits[key as any],
...vegetables[key as any],
}
}
setState(updatedContents)
}, [fruits, vegetables])
console.log('contents', contents)
console.log('contents length', contents.length)
useEffect executes after each render.
So the order of operations in your example is:
In Chrome's dev tools, javascript arrays/objects are displayed by their reference, evaluated lazily. What this means is that if something is added to the array/object later, and if you expand it later than when it was printed, you'll see the new data.
That answers the why.
As a solution, here's what you can do instead:
const [contents, setContents] = useState([]);
useEffect(() => {
const newContents = [];
for(const key of Object.keys(fruits)) {
newContents.push({
...fruits[key as any],
...vegetables[key as any],
});
setContents(newContents);
}
}, [fruits, vegetables, contents])
console.log('contents length', contents.length);
You'll see the appropriate console log once the state updates.