I am currently working on a simple todo crud app. I just cannot seem to get my data to be put out on the screen.
const Home = () => {
const [todos,setTodos] = useState([]);
const getTodos = async () =>{
const querySnapshot = await getDocs(collection(db, "todos"));
querySnapshot.forEach((doc) => {
setTodos([...todos,doc.data()])
console.log(doc.data())
console.log(todos)
});
}
useEffect(()=>{
getTodos();
},[])
return (
<div>Home</div>
)
}
Now the console.log(doc.data()) shows every dataset alright, but the todos array either gets just the first value assigned or returns an empty array.
Any ideas?
2
Answers
instead of using
setTodos([...todos,doc.data()])
try this
State setter operations are asynchronous, calling
setTodos
doesn’t change what’s in the array yourtodos
variable points to. Instead, it schedules a new call to your component function in which you’ll get the new data fromuseState
. (More in this answer.) That’s why both yourconsole.log(todos)
and your repeated calls tosetTodos
aren’t working: Both are using oudated information fromtodos
.When setting state based on existing state (your current array), it’s usually best to use the callback form of the state setter. So the minimal change would be:
That would work, but rather than calling
setTodos
in a loop, you might want to do the loop and then call the setter once when you’re done.I don’t use Firebase, but Nick Parsons found and posted this link saying you can get the docs as an array via a
docs
property. So you can callmap
on that array: