Use React Context as in the first place

This commit is contained in:
aronmal 2023-04-26 13:49:15 +02:00
parent f97b3a622a
commit 2ed943857e
Signed by: aronmal
GPG key ID: 816B7707426FC612
4 changed files with 56 additions and 18 deletions

View file

@ -4,23 +4,21 @@ import useGameState from "@lib/hooks/useGameState"
import { Fragment, useEffect, useState } from "react" import { Fragment, useEffect, useState } from "react"
function LobbyFrame({ openSettings }: { openSettings: () => void }) { function LobbyFrame({ openSettings }: { openSettings: () => void }) {
const { gameProps } = useGameState() const { payload } = useGameState().gameProps
const [dots, setDots] = useState(1) const [dots, setDots] = useState(1)
const { gamePin, player1, player2 } = gameProps.payload
useEffect(() => { useEffect(() => {
if (player2) return if (payload?.player2) return
const interval = setInterval(() => setDots((e) => (e % 3) + 1), 1000) const interval = setInterval(() => setDots((e) => (e % 3) + 1), 1000)
return () => clearInterval(interval) return () => clearInterval(interval)
}, [player2]) }, [payload?.player2])
return ( return (
<div className="mx-32 flex flex-col self-stretch rounded-3xl bg-gray-400"> <div className="mx-32 flex flex-col self-stretch rounded-3xl bg-gray-400">
<div className="flex items-center justify-between border-b-2 border-slate-900"> <div className="flex items-center justify-between border-b-2 border-slate-900">
<Icon src="speech_bubble.png">Chat</Icon> <Icon src="speech_bubble.png">Chat</Icon>
<h1 className="font-farro text-5xl font-medium"> <h1 className="font-farro text-5xl font-medium">
Game-PIN: <span className="underline">{gamePin?.pin}</span> Game-PIN: <span className="underline">{payload?.gamePin?.pin}</span>
</h1> </h1>
<Icon src="gear.png" onClick={openSettings}> <Icon src="gear.png" onClick={openSettings}>
Settings Settings
@ -29,13 +27,16 @@ function LobbyFrame({ openSettings }: { openSettings: () => void }) {
<div className="flex items-center justify-around"> <div className="flex items-center justify-around">
<Player <Player
src="player_blue.png" src="player_blue.png"
text={player1?.name ?? "Spieler 1 (Du)"} text={payload?.player1?.name ?? "Spieler 1 (Du)"}
primary={true} primary={true}
edit={true} edit={true}
/> />
<p className="font-farro m-4 text-6xl font-semibold">VS</p> <p className="font-farro m-4 text-6xl font-semibold">VS</p>
{player2 ? ( {payload?.player2 ? (
<Player src="player_red.png" text={player2.name ?? "Spieler 2"} /> <Player
src="player_red.png"
text={payload?.player2.name ?? "Spieler 2"}
/>
) : ( ) : (
<p className="font-farro w-96 text-center text-4xl font-medium"> <p className="font-farro w-96 text-center text-4xl font-medium">
Warte auf Spieler 2 {Array.from(Array(dots), () => ".").join("")} Warte auf Spieler 2 {Array.from(Array(dots), () => ".").join("")}

View file

@ -1,14 +1,49 @@
import { GamePropsSchema } from "@lib/zodSchemas" import { GamePropsSchema } from "@lib/zodSchemas"
import { useSession } from "next-auth/react" import { useSession } from "next-auth/react"
import { useEffect, useState } from "react" import {
Dispatch,
ReactNode,
SetStateAction,
createContext,
useContext,
useEffect,
useState,
useMemo,
} from "react"
import { toast } from "react-toastify" import { toast } from "react-toastify"
function useGameState(initial?: GamePropsSchema) { const initialValue = { payload: null, hash: null }
const [gameProps, setGameProps] = useState<GamePropsSchema>(
initial ?? { payload: {}, hash: "" } interface gameContext {
gameProps: GamePropsSchema
setGameProps: Dispatch<SetStateAction<GamePropsSchema>>
}
export const gameContext = createContext<gameContext>({
gameProps: initialValue,
setGameProps: () => {},
})
export function GameContextProvider({ children }: { children: ReactNode }) {
const [gameProps, setGameProps] = useState<GamePropsSchema>(initialValue)
const value = useMemo<gameContext>(
() => ({ gameProps, setGameProps }),
[gameProps, setGameProps]
) )
return <gameContext.Provider value={value}>{children}</gameContext.Provider>
}
function useGameState(initial?: GamePropsSchema) {
const { gameProps, setGameProps } = useContext(gameContext)
const { data: session, status } = useSession() const { data: session, status } = useSession()
useEffect(() => {
if (!initial) return
setGameProps(initial)
}, [initial, setGameProps])
useEffect(() => { useEffect(() => {
if (status === "loading") return if (status === "loading") return
if (!session) if (!session)

View file

@ -22,8 +22,8 @@ export const CreateSchema = z
.strict() .strict()
export const GamePropsSchema = z.object({ export const GamePropsSchema = z.object({
payload: CreateSchema, payload: CreateSchema.nullable(),
hash: z.string(), hash: z.string().nullable(),
}) })
export type GamePropsSchema = z.infer<typeof GamePropsSchema> export type GamePropsSchema = z.infer<typeof GamePropsSchema>

View file

@ -2,7 +2,7 @@ import "../styles/App.scss"
import "../styles/globals.scss" import "../styles/globals.scss"
import "../styles/grid2.scss" import "../styles/grid2.scss"
import "../styles/grid.scss" import "../styles/grid.scss"
import { CreateSchema } from "@lib/zodSchemas" import { GameContextProvider } from "@lib/hooks/useGameState"
import { SessionProvider } from "next-auth/react" import { SessionProvider } from "next-auth/react"
import type { AppProps } from "next/app" import type { AppProps } from "next/app"
import { ToastContainer } from "react-toastify" import { ToastContainer } from "react-toastify"
@ -14,8 +14,10 @@ export default function App({
}: AppProps) { }: AppProps) {
return ( return (
<SessionProvider session={session}> <SessionProvider session={session}>
<Component {...pageProps} /> <GameContextProvider>
<ToastContainer /> <Component {...pageProps} />
<ToastContainer />
</GameContextProvider>
</SessionProvider> </SessionProvider>
) )
} }