Following code to fetch data from firebase firestore and set to a state ‘products’ in useEffect :
const { firebase } = useContext(FirebaseContext)
const [products, setProducts] = useState([])
const db=firebase.firestore();
useEffect(() => {
const unsubscribe = db.collection("products").onSnapshot((snapshot) => {
const newProducts = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
setProducts(newProducts);
console.log( products);
});
return () => unsubscribe();
}, []);
when first render products is consoling empty array.(data are correctly fetching from firestore and coming to ‘newProducts’ as array of objects).
during running, if something is changed in the code, server restarts, and now products state is consoling correctly..
and when refreshing browser, products are again consoling empty array..
I am expecting ‘products’ state is setting the values from firestore in the first working of useEffect
I came to this state updation on rendering my component as follows..
return
<div>
<h4>{product.name}</h4>
<p> {product.price}</p>
<p>{product.type}</p>
</div>
})
}
All these are not running since products state is empty on initial render…
Hint: its because of asynchronous nature of setproduct().
How can i make the code in such a way that, page is loaded only after setting the state..
How can i solve this issue..?
3
Answers
it’s because component is not rerendered yet and Products state is still showing previous value,
if you want to see it’s value use it outside of useffect or log prevState in setProduct callback to see it’s value
like this :
or you can use another useEffect to see it’s new value, like this:
Move the
console.log(products)
to right after declaring your product’s useState hook.State updates in react (which is
setState
) can happen asynchronously. Therefore, there is no guarantee the next line has the updated state. What you really care about is the state when the component rendersYou can conditionally render the component based on any state variable let’s say productLoading.
You can use the useState hook and a state variable productLoading to solve this issue.
You can set the productLoading to true at the beginning of the component and set it to false after the state products has been set.
Here’s an example of how you could implement this:
This will enable to render the component only after products data is available