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)