Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

164
Views
react useState only stores the last document

I am working on a react Netflix clone web app and I have stored some data on Firestore for making a favorite list. When I fetched data from Firestore and try to store in a state, some error occured.

There were about four documents in firebase but I only got the last one every time I try

I have included key to the map and try to give the state empty string as initial value, I tried spread operator but none of them worked

firestore is working well as i see those documents on console

const [movie, setMovie] = useState([])

useEffect(() => {
async function fetchData() {

  const q = query(collection(db, "movie"));
  const querySnapshot = await getDocs(q);
  querySnapshot.forEach((doc) => {

    setMovie([...movie, doc.data().Details])
    console.log(doc.data().Details)
    console.log(movie)
  });
}

fetchData()
about 4 years ago · Juan Pablo Isaza
3 answers
Answer question

0

Your fetchData function closes over movie, which means it only sees the movie that existed when the function was created (you haven't shown enough to be sure, but I'm guessing you have an empty dependencies array on that useEffect, so that would be an always-empty movie). Doing setMovie([...movie, doc.data().Details]) just spreads that empty movie and then adds the one final document.

Instead, two things:

  1. Whenever updating state based on existing state, it's best to use the callback form of the setter so that you get the up-to-date version of the state you're updating.

  2. Collect the documents, then do just one setter call.

const [movies, setMovies] = useState([])

useEffect(() => {
    async function fetchData() {
        const q = query(collection(db, "movie"));
        const querySnapshot = await getDocs(q);
        setMovies(previousMovies => [
            ...previousMovies,
            ...querySnapshot.map((doc) => doc.data().Details)
        ]);
    }

    fetchData();
}, []); // <== I've assumed this

(Note I've made it a plural, since there's more than one movie.)

(I don't use MongoDB, but I've assumed from the forEach that querySnapshot is an array and so it has map. If not, it's easy enough to create the array, use forEach to push to it, and then do the setMovies call.)


But there's another thing: You should allow for the possibility your component is unmounted before the query completes. If your getDocs has a way to cancel its operation, you'll want to use that. For instance, if it accepted an AbortSignal, it might look like:

const [movies, setMovies] = useState([])

useEffect(() => {
    async function fetchData() {
        const controller = new AbortController();
        const { signal } = controller;
        const q = query(collection(db, "movie"));
        const querySnapshot = await getDocs(q, signal);
        if (!signal.aborted) {
            setMovies(previousMovies => [
                ...previousMovies,
                ...querySnapshot.map((doc) => doc.data().Details)
            ]);
        }
    }

    fetchData();
    return () => {
        controller.abort();
    };
}, []);

But if there's some other cancellation mechanism, naturally use that.

If there's no cancellation mechanism, you might use a flag so you don't try to use the result when it won't be used for anything, but that may be overkill. (React has backed off complaining about it when you do a state update after the component is unmounted, as it was usually a benign thing to do.)

about 4 years ago · Juan Pablo Isaza Report

0

for a start, I suggest you to do something like the following:

const [movie, setMovie] = useState([])

useEffect(() => {
async function fetchData() {

  const q = query(collection(db, "movie"));
  const querySnapshot = await getDocs(q);
  setMovie(querySnapshot.flatMap(elt=>elt.data().Details));
}

fetchData()
about 4 years ago · Juan Pablo Isaza Report

0

It's because you update your state on forEach loop, you start from first doc until the last one, in the end you set the last movie, that's why you have everytime the last doc on your state.

First of all don't update state too frequently, it creates app performance problems.

To fix it (based on your example):

     let movies=[]
     querySnapshot.forEach((doc) => {
        movies([...movies, doc.data().Details]);
 //or   movies.push(doc.data().Details);
      });
     setMovie(movies);
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!