Home > Back-end >  How to retrieve data using useState from Firebase?
How to retrieve data using useState from Firebase?

Time:04-18

I have few React Components :

MainPage.jsx

import Hotels from "./Hotels";
import WelcomePage from "./WelcomePage";

import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.0/firebase-app.js";
import {
  getFirestore,
  collection,
  getDocs,
  addDoc,
} from "https://www.gstatic.com/firebasejs/9.6.0/firebase-firestore.js";
import {
  getAuth,
  signInWithEmailAndPassword,
  createUserWithEmailAndPassword,
  onAuthStateChanged,
  signOut,
} from "https://www.gstatic.com/firebasejs/9.6.0/firebase-auth.js";
import { useState } from "react";

function MainPage() {
  const [hotels, getHotels] = useState([]);

  async function fetchHotels() {
    const firebaseConfig = {
      apiKey: "AIzaSyCHr3-x82i4RcGewtRs3XQ02Ps15Vm6ukQ",
      authDomain: "webapp-48b9a.firebaseapp.com",
      projectId: "webapp-48b9a",
      storageBucket: "webapp-48b9a.appspot.com",
      messagingSenderId: "889223227604",
      appId: "1:889223227604:web:aca93f8aa7b031fdfe7341",
    };

    const app = initializeApp(firebaseConfig);
    const db = getFirestore(app);
    const querySnapshot = await getDocs(collection(db, "reviews"));
    querySnapshot.forEach((doc) => {
      hotels.push(doc.data());
    });
    console.log(hotels);
  }

  fetchHotels();

  return (
    <main className="content">
      <Hotels hotels={hotels} />
    </main>
  );
}

export default MainPage;


Hotels.jsx

import Hotel from "./Hotel";

function Hotels(props) {
  const { hotels = [] } = props;

  return (
    <div className="Hotels">
      {hotels.map((hotel, id) => (
        <Hotel key={id} {...hotel} />
      ))}
    </div>
  );
}

export default Hotels;

Hotel.jsx

function Hotel(props) {
  const { name, img, localization, stars, review, author } = props;

  return (
    <div className="Hotel_card">
      <h2 className="Hotel_name">{name}</h2>
      <img className="Hotel_img" src={img} alt="hotel_img" />
      <h3 className="Hotel_localization">{localization}</h3>
      <p className="Hotel_stars">{stars}</p>
      <p className="Hotel_review">{review}</p>
      <h5 className="Hotel_author">Wroten by {author}</h5>
    </div>
  );
}

export default Hotel;

Nothing is displayed right now because Hotel.jsx doesn't see the data. console.log(hotels) in MainPage.jsx outputs this object

console.png

Question - How to display the data?

I guess I'm using useState incorrectly because Hostel.jsx doesn't receive any data

CodePudding user response:

First you shout put fetchHotels() in useEffect:

replace

fetchHotels();

with

useEffect(() => {
   fetchHotels();
}, []);

Then, You can not push to react state array directly,

replace

querySnapshot.forEach((doc) => {
    hotels.push(doc.data());
});

with:

let list = [];
await querySnapshot.forEach((doc) => {
   list.push(doc.data());
});
getHotels(list);

Finally, you have another error in

<h3 className="Hotel_localization">{hotel.localization}</h3>

localization is an object. Objects are not valid as a React child

So, it should be:

<h3 className="Hotel_localization">
    {localization._lat}, {localization._long}
</h3>

Or something like that

Demo: https://codesandbox.io/s/blissful-kate-7cmu3s

CodePudding user response:

You can't pass props like this : {...hotel}

Try this:

 <div className="Hotels">
      {hotels.map((hotel, id) => (
       return <Hotel key={id} hotel={hotel} />
      ))}
    </div>

and in your component get the prop hotel and from there pass the data :

function Hotel(props) {
  const { hotel } = props;

  return (
    <div className="Hotel_card">
      <h2 className="Hotel_name">{hotel.name}</h2>
      <img className="Hotel_img" src={hotel.img} alt="hotel_img" />
      <h3 className="Hotel_localization">{hotel.localization}</h3>
      <p className="Hotel_stars">{hotel.stars}</p>
      <p className="Hotel_review">{hotel.review}</p>
      <h5 className="Hotel_author">Wroten by {hotel.author}</h5>
    </div>
  );
}

CodePudding user response:

In React you can NOT mutate the state directly or it won't be able to listen to the changes on the state and re-render the component accordingly to the changes. So, in the fetchHotels function once you fetch the data you need to use the setState method provided by the react state to update the hotels state correctly:

const _hotels = [];
querySnapshot.forEach((doc) => {
 _hotels.push(doc.data());
});
getHotels(_hotels); //change the name of the method to setHotels to be more explicative
  • Related