Passing Data through our React Code
Let's pass data through React in this lesson.
We'll cover the following...
The Row
component
Following our change through, the VenueBody
component doesn’t change much, it merely takes in the extra values and passes them along, giving each row its corresponding RowData
:
Press + to interact
import * as React from "react"import Row from "components/row"import { VenueData } from "components/venue"interface VenueBodyProps {concertId: numberrowCount: numberseatsPerRow: numberticketsToBuyCount: numbervenueData: VenueData}const rowItems = ({concertId,rowCount,seatsPerRow,ticketsToBuyCount,venueData,}) => {const rowNumbers = Array.from(Array(rowCount).keys())return rowNumbers.map((rowNumber: number) => (<RowconcertId={concertId}key={rowNumber}rowData={venueData[rowNumber]}rowNumber={rowNumber}seatsPerRow={seatsPerRow}ticketsToBuyCount={ticketsToBuyCount}/>))}export const VenueBody = (props: VenueBodyProps): React.ReactElement => {return (<table className="table"><tbody>{rowItems(props)}</tbody></table>)}export default VenueBody
The Row
component carries a lot of load here. It maintains a client-side status of each seat that is based on its ticket status and also the number of tickets the user is looking to buy, so as to prevent buying tickets so close to an already sold ticket that we can’t buy an entire block. It also has the click handler invoked when a user clicks on a seat.
Here’s the new version of the row:
Press + to interact
import * as React from "react"import Rails from "@rails/ujs"import Seat from "components/seat"import { RowData, TicketData } from "components/venue"interface RowProps {concertId: numberrowData: RowDatarowNumber: numberseatsPerRow: numberticketsToBuyCount: number}const Row = (props: RowProps): React.ReactElement => {const [seatStatuses, setSeatStatuses] = React.useState(Array.from(Array(props.seatsPerRow).keys()).map(() => "unsold"))React.useEffect(() => {if (props.rowData) {setSeatStatuses(props.rowData.map((ticketData: TicketData) => ticketData.status))}}, [props.rowData])function isSeatValid(seatNumber): boolean {if (seatNumber + props.ticketsToBuyCount > props.seatsPerRow) {return false}for (let i = 1; i < props.ticketsToBuyCount; i++) {const seatStatus = seatStatuses[seatNumber + i]if (seatStatus === "held" || seatStatus === "purchased") {return false}}return true}function validSeatStatus(seatNumber): string {const seatStatus = seatStatuses[seatNumber]if (seatStatus === "held" || seatStatus === "purchased") {return seatStatus} else {return isSeatValid(seatNumber) ? "unsold" : "invalid"}}function newState(oldStatus: string): string {if (oldStatus === "unsold") {return "held"} else if (oldStatus === "held") {return "unsold"} else {return "invalid"}}function updateSeatStatus(seatNumber: number): string[] {return seatStatuses.map((status: string, index: number) => {if (index >= seatNumber &&index < seatNumber + props.ticketsToBuyCount) {return newState(seatStatuses[seatNumber])} else {return status}})}function onSeatChange(seatNumber: number): void {const validStatus = validSeatStatus(seatNumber)if (validStatus === "invalid" || validStatus === "purchased") {return}const newSeatStatuses = updateSeatStatus(seatNumber)setSeatStatuses(newSeatStatuses)fetch(`/shopping_carts`, {method: "POST",headers: {"X-CSRF-Token": Rails.csrfToken(),"Content-Type": "application/json",},body: JSON.stringify({concertId: props.concertId,row: props.rowNumber + 1,seatNumber: seatNumber + 1,status: newSeatStatuses[seatNumber],ticketsToBuyCount: props.ticketsToBuyCount,}),})}const seatItems = Array.from(Array(props.seatsPerRow).keys()).map((seatNumber: number) => {return (<SeatclickHandler={onSeatChange}key={seatNumber}seatNumber={seatNumber}status={validSeatStatus(seatNumber)}/>)})return <tr className="h-20">{seatItems}</tr>}export default Row
There are some small changes here because we are passing concertId
and rowData
into the props. ...