Reputation: 19
I am having trouble trying to figure out how to get map data from Firestore in reactjs. My code keeps erroring saying "Objects are not valid as a React". Can someone point me to an example or show me one with my database below?
import React, { useState, useEffect } from "react";
import { firestore } from "../../../FireBase/FireBase";
import CartItem from "./CartItem";
const CartPage = (props) => {
const [cart, setCart] = useState(null);
useEffect(() => {
const fetchCart = async () => {
const doc = await firestore
.collection("Users")
.doc("CfL5uszL3CTE1nIQTgDrKK5q4OV2")
.get();
const data = doc.data();
console.log("data " + data);
if (!data) {
// document didn't exist
console.log("hit null");
setCart(null)
} else {
console.log("hit");
setCart(data.cart);
}
console.log("cart " + cart);
}
fetchCart();
}, []);
if (!cart) {
// You can render a placeholder if you like during the load, or just return null to render nothing.
return null;
}
return (
<div className="cartpage">
<h1>cart</h1>
<div className="cart">
{cart.map(cartItem => (
<div key={cartItem.id}>{cartItem.name}</div>
))}
</div>
</div>
);
};
export default CartPage;
Upvotes: 0
Views: 1272
Reputation: 84922
The error your getting is because you're returning a promise from your component (You've made it an async function, and async functions return promises). Promises and other arbitrary objects cannot be returned from rendering in react. You need to have a state variable for holding your data. On the first render, you'll have no data, and then you'll use a useEffect to fetch the data and update the state
Additionally, you have some mistakes with how you're trying to get the data and access it. You're calling .get("Cf...V2")
, but .get doesn't take a parameter. If you want to specify which document to get, you use the .doc()
function for that. .get() will then return a promise, so you need to await that before trying to access any properties on it. The data you get will be an object with all the properties on the right hand side of your screenshot, and you will need to pluck the cart property out of that.
In short, i recommend something like the following:
const CartPage = (props) => {
const [cart, setCart] = useState(null);
useEffect(() => {
const fetchCart = async () => {
const doc = await firestore
.collection("Users")
.doc("CfL5uszL3CTE1nIQTgDrKK5q4OV2")
.get();
const data = doc.data();
if (!data) {
// document didn't exist
setCart(null)
} else {
setCart(data.cart);
}
}
fetchCart();
}, []);
if (!cart) {
// You can render a placeholder if you like during the load, or just return null to render nothing.
return null;
}
return (
<div className="cartpage">
<h1>cart</h1>
<div className="cart">
{cart.map(cartItem => (
<div key={cartItem.id}>{cartItem.name}</div>
))}
</div>
</div>
);
};
Upvotes: 1
Reputation: 2053
I don't think so that you can create async component in this way. What you return in your component should be simple JSX code. If you want to do something asynchronously inside component you should wrap this inside useEffect hook.
const CartPage = (props) => {
const [ cart, setCart ] = useState(null)
useEffect(() => {
const inner = async () => {
const ref = await firestore
.collection("Users")
.get("CfL5uszL3CTE1nIQTgDrKK5q4OV2").cart;
setCart(
ref.map((item) => ({
id: item.id,
name: item.name
}))
);
};
inner();
}, []);
return (
<div className="cartpage">
<h1>cart</h1>
<div className="cart"></div>
</div>
);
};
Upvotes: 0