Using Props With Context
Continue refactoring React code with contexts in this lesson.
We'll cover the following...
Row
component
The Row
component is no longer tracking the state of its seats so it can be much simpler:
Press + to interact
import * as React from "react"import Seat from "../components/seat"import { IsVenueContext, VenueContext } from "./app"interface RowProps {rowNumber: number}const Row = ({ rowNumber }: RowProps) => {const context = React.useContext<IsVenueContext>(VenueContext)const seatItems = Array.from(Array(context.state.seatsInRow).keys()).map(seatNumber => {return (<Seatkey={seatNumber + 1}seatNumber={seatNumber + 1}rowNumber={rowNumber + 1}/>)})return <tr>{seatItems}</tr>}export default Row
Note that we haven’t totally abandoned the use of props—the row number of each individual row isn’t a part of the global state, so we pass it to that row as a prop. Similarly, the Seat
component will get its row and seat number as props.
Seat
component
The Seat
component takes on all the application logic for seat status, and so it picks up some of the complexity that the other components have lost:
Press + to interact
import * as React from "react"import styled from "styled-components"import { TicketData } from "./venue_reducer"import { IsVenueContext, VenueContext } from "./app"const stateColor = (status: string): string => {if (status === "unsold") {return "white"} else if (status === "held") {return "green"} else if (status === "purchased") {return "red"} else {return "yellow"}}interface SquareProps {status: stringclassName?: string}const ButtonSquare = styled.span.attrs({ className: "button" })<SquareProps>`background-color: ${props => stateColor(props.status)};transition: all 1s ease-in-out;border-width: 3px;&:hover {background-color: ${props =>props.status === "unsold" ? "lightblue" : stateColor(props.status)};}`interface SeatProps {seatNumber: numberrowNumber: number}export const Seat = ({ seatNumber, rowNumber }: SeatProps) => {const context = React.useContext<IsVenueContext>(VenueContext)const seatMatch = (ticketList: TicketData[], exact = false): boolean => {for (const heldTicket of ticketList) {const rowMatch = heldTicket.row == rowNumberconst seatDiff = heldTicket.number - seatNumberconst diff = exact ? 1 : context.state.ticketsToBuyconst seatMatch = seatDiff >= 0 && seatDiff < diffif (rowMatch && seatMatch) {return true}}return false}const currentStatus = (): string => {if (seatMatch(context.state.otherHeldTickets, true)) {return "purchased"}if (seatMatch(context.state.myHeldTickets, true)) {return "held"}if (seatMatch(context.state.otherHeldTickets) ||seatMatch(context.state.myHeldTickets) ||seatNumber + context.state.ticketsToBuy - 1 > context.state.seatsInRow) {return "invalid"}return "unsold"}const onSeatChange = (): void => {const status = currentStatus()if (status === "invalid" || status === "purchased") {return}const actionType = status === "unsold" ? "holdTicket" : "unholdTicket"context.dispatch({ type: actionType, seatNumber, rowNumber })}return (<td><ButtonSquare status={currentStatus()} onClick={onSeatChange}>{seatNumber}</ButtonSquare></td>)}export default Seat
A lot of this is similar to the previous version. The new bits are the currentStatus
function and its ...