Home > Back-end >  Problem having updating useState in React
Problem having updating useState in React

Time:10-22

I am having a problem assigning data to useState by fetching data using reference type value from firebase.

const [preOil, setPreOil] = useState([]);
const [oilChange, setOilChange] = useState([]);

useEffect(() => {
getDocs(query(collection(db, "oil"), orderBy("timestamp"))).then(
  (snapshot) => {
    setPreOil(
      snapshot.docs.map((doc) => ({
        id: doc.id,
        ...doc.data(),
      }))
    );
  }
);
}, []);


useEffect(() => {
let current = preOil.length > 0 ? [...preOil] : [];

current.map((_oil, i) => {
  getDoc(_oil.oilReference).then((oilRef) => {
    current[i].oilReference = oilRef.data();
  });
});

setOilChange(current);
 }, [preOil]);

In the first useEffect, the data is fetched successfully in this form,

preOil = {
        id:"RxbAOAIs8d3kGOHNskJ4",
        oilReference: Ta {converter: null, _key: ut, type: 'document', firestore: Na},
        customerName: "USAMA",
}

In the second useEffect based on [preOil], I need to reassign the oilReference with the data fetched from firestore through its reference(oilReference), The data is successfully fetched from the database and assigned to current but The main problem is when I set to state setOilChange(current) it updates my oilChange state when I inspect in inspect tools in chrome but in JSX the changes don't reflect

  • I am updating state in useEffect
  • I am having desired data assigned in a local variable and assign that variable to state

Then What am I missing?

CodePudding user response:

In your second useEffect(), more specifically, in

current.map((_oil, i) => {
  getDoc(_oil.oilReference).then((oilRef) => {
    current[i].oilReference = oilRef.data();
  });
});
setOilChange(current);

You are mutating the content of the current variable. This mutation, because it is async, will happen after the setOilChange call. Such mutation will thus not trigger a re-render.

What you need is to instead first wait for all the docs to be loaded and only after that set the state. Example:

const docs = current.map((_oil, i) => {
  return getDoc(_oil.oilReference).then((oilRef) => { // changed here
    return {                                          // changed here
      ...current[i],                                  // changed here
      oilReference: oilRef.data()                     // changed here
    }                                                 // changed here
  });                                                 // changed here
});

Promise.all(docs).then(() => {
  setOilChange(current);
});

Also notice I didn't mutate current, rather I returned a new object. This is not mandatory but just a best practice overall.

  • Related