I am working on a practice problem and when I console log the response body of my get request it shows that I am fetching the correct object but when I console log the object in the component I am calling the get request in the value reads as undefined.
This is my component
const ReservationPage = () => {
const [reservations, setReservations] = useState([]);
const [apiError, setApiError] = useState();
const [roomTypes, setRoomTypes] = useState();
useEffect(() => {
getAllReservations(setReservations);
getAllRoomTypes(setRoomTypes);
console.log(roomTypes);
console.log(reservations);
const reservationsWithNames = [];
reservations.forEach((reservation) => {
console.log(reservation);
const newEntry = {
id: reservation.id,
guestEmail: reservation.guestEmail,
roomType: roomTypes[reservation.roomTypeId - 1].name,
checkInDate: reservation.checkInDate,
numberOfNights: reservation.numberOfNights,
totalCost: roomTypes[reservation.roomTypeId - 1].rate * reservation.numberOfNights
};
reservationsWithNames.splice(0, newEntry);
});
console.log(reservationsWithNames);
}, []);
return (
<div className={styles.pageContainer}>
{apiError
&& <p className={styles.errMsg} name="errMsg" data-testid="errMsg">{Constants.API_ERROR}</p>}
<div>
<div className={styles.titleContainer}>
<h1 className={styles.title}>Maintenance</h1>
<NavLink to="/reservations/create">
<button
type="button"
name="createButton"
data-testid="createButton"
className={styles.createButton}
>
Create Reservation
</button>
</NavLink>
</div>
<div className={styles.pageBody}>
<table className={styles.table}>
<thead>
<tr>
<th>Action</th>
<th>ID</th>
<th>Guest Email</th>
<th>Room Type</th>
<th>Check In Date</th>
<th>Number of Nights</th>
<th>Total Cost</th>
</tr>
</thead>
<tbody>
{reservations.sort((a, b) => a.id - b.id).map((reservation) => (
<tr key={reservation.id} data-testid="reservation">
<td>
<NavLink className="test-btn-reserve" to="/reservations">
<Button data-testd="button" className={styles.btn}>
<EditIcon />
</Button>
</NavLink>
<NavLink className="test-btn-reserve" to="/reservations">
<Button data-testd="button" className={styles.btn}>
<DeleteIcon />
</Button>
</NavLink>
</td>
<td>{reservation.id}</td>
<td>{reservation.guestEmail}</td>
<td>{}</td>
<td>{reservation.checkInDate}</td>
<td>{reservation.numberOfNights}</td>
<td>{}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
);
};
and these are my requests
export const getAllReservations = async (setReservations) => {
await HttpHelper('/reservations', 'GET')
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw new Error(Constants.API_ERROR);
})
.then((body) => {
console.log(body);
setReservations(body);
})
.catch(() => {
console.log('here');
});
};
export const getAllRoomTypes = async (setRoomType) => {
await HttpHelper('/room-types', 'GET')
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw new Error(Constants.API_ERROR);
})
.then((body) => {
console.log(body);
setRoomType(body);
})
.catch(() => {
});
};
finally this is the result I get on run
CodePudding user response:
Your useEffect is synchronous, hence before getAllRoomTypes calls setRoomTypes, your console.log is fired before your state is changed and because the roomTypes is initialized as undefined, you get undefined in console. Either use async await or put business logic in another effect which runs when roomTypes or reservations change
CodePudding user response:
Yes you should do something like @sandeep.kgp said and also you can put some conditions to render the object like,
(reservation !== undefined && reservation.key)
