Galactic Ranger
Galactic Ranger

Reputation: 882

How to update react context after pulling data from firebase

Hey everyone pretty new to React hooks. I am simply trying to set some reviews that I retrieve from Firebase but cant seem to get it working. I tried a few solutions and I am struggling to get it working any help would be appreciated.

import React, {useContext, useEffect, useState} from 'react';
import firebase from "firebase";
import ReviewsContext from "./review-context";

const Reviews = () => {
const db = firebase.firestore();
let reviews = useContext(ReviewsContext);
let [reviewsLoaded, setReviewsLoaded] = useState(false);

function getReviews(){
  db.collection('reviews')
    .get()
    .then((snapshot) => {
      let dataArray = [];

      snapshot.docs.forEach(doc => {
        dataArray.push(doc.data());
      });

      reviews = dataArray;
      setReviewsLoaded(true);
      console.log('reviews', reviews); // logs the correct amount of reviews
    })
  }

  function renderReviews() {
  console.log('renderReviews reviewsLoaded', reviewsLoaded); // is true
  console.log('renderReviews reviews length', reviews.length); // is 0
  if(reviewsLoaded) {
    reviews.map((data) => {
      return (
        <li key={data.name}>
          <h3>{data.name}</h3>
          <p>{data.position}</p>
        </li>
      )
    });
  }
  else {
    return false
   }
  }

  useEffect(() => {
    getReviews(); // this seems to fire before renderReviews
  }, []);


  return (
   <div>
     <ul>
       {renderReviews()}
     </ul>
   </div>
  )
};

export default Reviews;

Upvotes: 1

Views: 929

Answers (1)

Franrey Saycon
Franrey Saycon

Reputation: 667

In this case, the context should be stateful. The way you're doing it currently won't work since context on render will always revert to reviews being empty. Your Provider component that gives that ReviewContext should be patterned like below.

import React, { createContext, useState } from "react"

const ReviewContext = createContext()

const ReviewProvider = ({children}) => {

  const [reviews, setReviews] = useState([])

  return (
    <ReviewContext.Provider value={{
      reviews: reviews,
      setReviews: reviews => setReviews(reviews),
    }}>
      {children}
    </ReviewContext.Provider> 
  )
}

export default ReviewProvider
export { ReviewContext }

Now, you may do const { reviews, setReviews } = useContext(ReviewContext); Just call setReviews whenever you want to update reviews in the context.

It's actually stated in the docs as well as I searched it. https://reactjs.org/docs/context.html#dynamic-context

Upvotes: 1

Related Questions