skip to Main Content

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


  1. 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 :

      useEffect(() => {
        const unsubscribe = db.collection('products').onSnapshot(snapshot => {
          const newProducts = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }));
          setProducts(newProducts);
          setProducts((prevState)=>{
            console.log(prevState)
            return prevState
          });
        });
    
        return () => unsubscribe();
      }, []);
    

    or you can use another useEffect to see it’s new value, like this:

      useEffect(()=>{
        console.log(products);
      },[products])
    
    Login or Signup to reply.
  2. 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 renders

    Login or Signup to reply.
  3. You 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:

    const { firebase } = useContext(FirebaseContext);
    const [products, setProducts] = useState([]);
    const [loading, setLoading] = useState(true);
    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);
            setLoading(false);
          });
        
          return () => unsubscribe();
        }, []);
        
        return (
          <div>
            {loading ? (
              <div>Loading...</div>
            ) : (
              <ul>
                {products.map((product) => (
                  <li key={product.id}>{product.name}</li>
                ))}
              </ul>
            )}
          </div>
        );
    

    This will enable to render the component only after products data is available

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search