I'm making a cinema app, where I will select seats in cinema hall and add tickets to the cart
Function to display cinema hall:
export default function CinemaHall(props) {
const row = props.row;
const seats = props.seats;
const hall = [];
const [isActive, setIsActive] = useState(false);
function getSeats(place) {
setIsActive(isActive => !isActive);
console.log("Row: " row, "Place: " place);
}
for(let i = 1; i < seats; i ) {
hall.push(
<div className="seats" onClick={() => getSeats(i)} style={{backgroundColor: isActive ? "rgb(255, 208, 0)" : "rgb(58, 130, 218)"}}></div>
)
}
return hall;
}
It returns my hall (look at image):
But if I click on the seat, then not one seat is repainted, but a whole row. How to fix it?
CodePudding user response:
There are a few things, but the main thing is that you'll need to maintain a separate "active" flag for each seat. For instance, you might have a Set
of active seats.
See comments for details and other notes:
export default function CinemaHall({ row, seats }) {
// Maintain a map of the seats that are "active"
const [seatsActive, setSeatsActive] = useState(new Set());
function toggleSeat(place) {
// Generally, use the callback form when updating state based on
// existing state
setSeatsActive((previous) => {
// Get a new set
const update = new Set(previous);
// Toggle this seat: remove it if it's in the set, add it if
// it isn't
if (update.has(place)) {
update.delete(place);
} else {
update.add(place);
}
console.log(`Row: ${row} Place: ${place} Active: ${update.has(place)}`);
return update;
});
}
const hall = [];
// If the first seat is `1`, you want to loop until `<= seats`, not
// just `< seats`, if you want `seats` number of seats
for (let seat = 1; seat <= seats; seat ) {
// Note the `key` prop -- it's important to include that in arrays
// managed by React. In this case, we can use the seat number, but
// beware there are many times you can't use an array index as a key!
// Note using `seatsActive.has(seat)` to see if the seat is "active"
hall.push(
<div
key={seat}
className="seats"
onClick={() => toggleSeat(seat)}
style={{ backgroundColor: seatsActive.has(seat) ? "rgb(255, 208, 0)" : "rgb(58, 130, 218)" }}
/>
// Note that in JSX (unlike HTML), you can self-close void
// element tags like `div`
);
}
return hall;
}
Re my note about using seat
as the key: It's fine here, but usually using a loop counter is not okay, details in this article linked from the React keys documentation.
Side note: I'd use a class, not inline styling, to indicate active seats:
<div
// ...
className={`seat ${seatsActive.has(seat) ? "active" : ""}`}
/>