...

/

Sharing State - Row & Seat Components

Sharing State - Row & Seat Components

Read about how to share state in the row component this lesson.

We'll cover the following...

The rows in the venue body are the same as before, except we are passing the number of tickets to buy as a new prop in the object.

The Row component has gotten a lot more functionality, some of which has been taken from the Seat component. In this version of the code, the status of a seat depends on the status of the seats next to it—if the tickets to buy number is two, then a set with an already sold seat next to it is not available. Because an individual seat can no longer contain all the data needed to ascertain it’s status, the status for the entire row now needs to be stored in the Row component.

Here’s the Row code:

Press + to interact
import * as React from "react"
import Seat from "../components/seat"
interface RowProps {
rowNumber: number
seatsInRow: number
ticketsToBuy: number
}
const Row = (props: RowProps) => {
const [seatStatuses, setSeatStatuses] = React.useState(
Array.from(Array(props.seatsInRow).keys()).map(() => "open")
)
function isSeatValid(seatNumber): boolean {
if (seatNumber + props.ticketsToBuy > props.seatsInRow) {
return false
}
for (let i = 1; i < props.ticketsToBuy; i++) {
if (seatStatuses[seatNumber + i] === "held") {
return false
}
}
return true
}
function validSeatStatus(seatNumber): string {
if (seatStatuses[seatNumber] === "held") {
return "held"
} else {
return isSeatValid(seatNumber) ? "open" : "invalid"
}
}
function newState(oldStatus: string): string {
if (oldStatus === "open") {
return "held"
} else if (oldStatus === "held") {
return "open"
} else {
return "invalid"
}
}
function onSeatChange(seatNumber: number): void {
if (validSeatStatus(seatNumber) === "invalid") {
return
}
setSeatStatuses(
seatStatuses.map((status, index) => {
if (index >= seatNumber && index < seatNumber + props.ticketsToBuy) {
return newState(seatStatuses[seatNumber])
} else {
return status
}
})
)
}
const seatItems = Array.from(Array(props.seatsInRow).keys()).map(
seatNumber => {
return (
<Seat
key={seatNumber}
seatNumber={seatNumber}
status={validSeatStatus(seatNumber)}
clickHandler={onSeatChange}
/>
)
}
)
return <tr>{seatItems}</tr>
}
export default Row

This component does two important things: First, it keeps track of the seat statuses in an array. Second, it defines a click handler to be executed when a seat is clicked. To make that work, the Row component passes that handler function as a prop to the Seat component, namely clickHandler.

The first thing that we need to do is we call the useState hook again on line 11, this time to create an array of seat statuses. The initial value, which is the argument to the useState call, is an array of open values, one for each seat in the row.

Using an array or an object as the value of the state in a useState call, rather than an individual value, is a little bit different than you might expect. It is important to keep in mind that the argument to the useState method is only applied to the state value the first time the component is drawn. When the component re-renders, that value is ignored. An implication of that is that, as a general rule, you don’t want the argument to the useState method to be dynamic. In our case, it’s just an array of open values since we don’t expect the number of seats in the row to change.

Later, in ...