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
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