I want to populate an array before render, and the render is conditional based on the length of the array.
If the length of the array > 0, do the render, otherwise don't.
But it seems that the length is always 0 becasue useEffect is asynchronous, so the render is never done.
Below is my code:
function OrderDetail(props) {
const {userInfo} = useSelector(state => state.user)
const [order, setOrder] = useState({});
const [items, setItems] = useState([]);
useEffect(()=>{
if(!userInfo){
props.history.push("/")
return
}
const fetchOrderAndItems = async () => {
// Get an order from backend.
const order = await axios.get("/api/orders/" + props.match.params.id, {
headers:{
authorization: "Bearer " + userInfo.token
}
});
const order_data = order.data
setOrder(order_data)
// Take out the id of all items in the order, retrieve each product from backend,
//push them in "items_array" and set it in the "items" state.
let items_array = [];
order_data.orderItems.forEach( async (orderItem) => {
const {data} = await axios.get("/api/products/" + orderItem.productId);
items_array.push(data);
})
console.log("items_array.length: " + items_array.length);
console.log(items_array);
setItems(items_array);
}
fetchOrderAndItems();
}, [userInfo]);
// For each item in the "items" state, return a <tr> element.
const itemsHtml = items.map(item => {
return <tr key={item._id}>
Something to display.
</tr>
})
// if itemsHtml.length > 0, render {itemsHtml}, otherwise display "Your cart is empty.".
// But what is displayed is always "Your cart is empty."
return <table className="table text-center">
<thead style={{border: "none"}}>
<tr>
<th style={{border: "none"}} scope="col"></th>
<th style={{border: "none"}} scope="col">Name</th>
<th style={{border: "none"}} scope="col">Price</th>
<th style={{border: "none"}} scope="col">Qty</th>
<th style={{border: "none"}} scope="col">Subtotal</th>
<th style={{border: "none"}} scope="col"></th>
</tr>
</thead>
{
itemsHtml.length > 0?
<tbody>
{itemsHtml}
</tbody>
:
<tbody>
<tr className="text-center">
<th className="text-center" scope="row" colSpan="6">Your cart is empty. </th>
</tr>
</tbody>
}
</table>
The output of the 2 lines of "console.log" is:

We can see that the length of items_array is 0 while there is content in it, and I think it is because it is asynchronous.
And I guess because the length is 0, so the conditional render of itemsHtml.length > 0? is never true, so the desired content is never rendered.
Could anyone teach me how to solve it?
Thanks