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.