Home > Enterprise >  React.js how to get an element and paint it a different color
React.js how to get an element and paint it a different color

Time:08-04

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):

enter image description here

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" : ""}`}
/>
  • Related