I need to use this information for my purchase completed page, but i get this error: Uncaught TypeError: Cannot read properties of undefined (reading '0')
My code is:
import { getFirestore } from "../firebase/firebase";
import { useParams } from "react-router-dom";
function ConfirmacionCompraPage() {
const {orderId} = useParams();
const [order, setOrder] = useState({});
useEffect(() => {
const db = getFirestore();
db.collection("ordenes")
.doc(orderId)
.get()
.then((res) => setOrder({ id: res.id, ...res.data() }));
}, [orderId]);
return (
<div>
<h2>Detalle de su compra: {order.items[0].item.paleta}</h2>
</div>
);
};
export default ConfirmacionCompraPage ;```
And my Firestore is:
[![Firestore][1]][1]
[1]: https://i.stack.imgur.com/cGdST.png
CodePudding user response:
The initial state of order
is an empty object:
const [order, setOrder] = useState({});
So order.items
is undefined
, and order.items[0]
is an attempt to read index 0
of undefined
.
You could set some initial state:
const [order, setOrder] = useState({ items: [{ item: { paleta: '' }}]});
Or perhaps use null checking (if it works with array indexing? I'm actually not certain at the moment):
<h2>Detalle de su compra: {order?.items?[0]?.item?.paleta}</h2>
Or perhaps conditionally render:
{
(order && order.items && order.items.length > 0 && order.items[0].item)
? <h2>Detalle de su compra: {order?.items?[0]?.item?.paleta}</h2>
: null
}
Any way you approach it, the main point here is that you're drilling very deep into an object without checking if that object has any of the properties you're using.
You might also simplify any of the above by only keeping the value paleta
in state instead of the entire order
object, if you only actually need that one value. So the state would be something like:
const [paleta, setPaleta] = useState('');
And you'd drill into the properties when setting it:
.then((res) => setPaleta(res.data().items[0].item.paleta));
And reference it more simply in rendering:
<h2>Detalle de su compra: {paleta}</h2>
Of course this is only if you're just using that one value. If this example is reduced for brevity and you actually need much more of the object then, yes, keep the whole object in state. But logically apply null checking in the rest of your rendering to make sure the object is populated before rendering it.
CodePudding user response:
Your error might be caused by {order.items[0].item.paleta}
, as the property of an undefined
object cannot be read.
Your order
state initially holds an empty object, which is the case upon first render and until your firebase
response provokes a rerendering via useEffect
.
- A solution would be to conditionally call your
{order.items[0].item.paleta}
as follows:
return (
<div>
{order && <h2>Detalle de su compra: {order?.items?[0]?.item?.paleta}</h2>}
</div>
);
or
return (
<div>
<h2>Detalle de su compra: {order ? order?.items?[0]?.item?.paleta : "dummy
temporary string"}</h2>}
</div>
);
If it still doesn't work then test with order && order?.items?.length && order?.items?[0]?.item && order?.items?[0]?.item?.paleta