A race condition is a correctness problem where concurrent operations produce results based on timing or ordering. In a bookings UI, an older response can arrive after a newer selection and overwrite the display. section 7.4.5
BookingsGrid response handling
When the selected bookable or week changes, useEffect starts another request. Mark each effect invocation current, update state only while it remains current, and return cleanup that invalidates it: `let doUpdate = true; ... if (doUpdate) setBookings(...); ... return () => doUpdate = false;`. section 7.4.5
Listing 7.13 The BookingsGrid component: 2. Effects
export default function BookingsGrid (
{week, bookable, booking, setBooking}
) {
// 1. Variables
useEffect(() => {
if (bookable) {
let doUpdate = true; #1
setBookings(null);
setError(false);
setBooking(null);
getBookings(bookable.id, week.start, week.end) #2
.then(resp => {
if (doUpdate) { #3
setBookings(transformBookings(resp)); #4
}
})
.catch(setError);
return () => doUpdate = false; #5
}
}, [week, bookable, setBooking]); #6
// 3. UI helper
// 4. UI
}
#1 Use a variable to track whether the bookings data is current.
#2 Call our getBookings data-fetching function.
#3 Check if the bookings data is current.
#4 Create a bookings lookup and assign it to state.
#5 Return a cleanup function to invalidate the data.
#6 Run the effect when the bookable or week changes.
Shows the complete effect lifecycle: request initiation, current-response checking, cleanup, and dependencies. section 7.4.5
Prevent race conditions in effects by:
- Returning cleanup before rerunning an effect or unmounting. section 4.4
- Defining async functions inside useEffect rather than making the effect callback async. section 4.2.4



















