So I have a problem with useContext in React. I want to update it in my parent component, then use it in child components. However, while the context seem to work properly inside my parent component, when I want to use it in the children, it’s undefined (still has its default value).
The code snippets that illustrate the problem:
LobbyContext.tsx
import React, {createContext, useState} from "react";
import { ILobby } from "@/components/GameIndex";
interface ILobbyContext {
lobby: ILobby | undefined;
setLobby: React.Dispatch<React.SetStateAction<ILobby | undefined>>;
}
export const LobbyContext = createContext<ILobbyContext>({
lobby: "",
setLobby: () => {
console.log("old function")}
});
export function LobbyProvider({ children }: { children: React.ReactNode }) {
const [lobby, setLobby] = useState<ILobby | undefined>();
return (
<LobbyContext.Provider value={{ lobby, setLobby }}>
{children}
</LobbyContext.Provider>
);
}
/game/[id].tsx
import {LobbyProvider} from "@/context/LobbyContext";
import GameIndex from "@/components/GameIndex"
const Index = () => {
return (
<LobbyProvider>
<GameIndex />
</LobbyProvider>
);
};
export default Index;
fragments of GameIndex.tsx
const { lobby, setLobby } = useContext(LobbyContext);
/*...*/
useEffect(() => {
fetch(`http://localhost:8080/api/lobby/${lobbyId}`)
.then(data => {
setLobby(data);
}
, [lobby, setLobby] }
/*...*/
return (
{lobby !== undefined ? <Scoreboard/> : <div>Loading...</div>}
);
Scoreboard.tsx
import {LobbyContext} from "@/context/LobbyContext";
const Scoreboard = () => {
const {lobby, setLobby} = useContext(LobbyContext);
return (
<div className={"scoreboard flex-col"}>
{lobby}
</div>
);
}
ironically, Scoreboard renders, because lobby
is defined inside of GameIndex.tsx, but inside of Scoreboard, it’s undefined…
What am I doing wrong?
2
Answers
I solved this issue - it turns I have used ContextProvider twice - both in /game/[id].tsx and GameIndex.tsx. By removing the GameIndex provider, the context now works as intended.
When processing the fetch request, you should parse the retrieved data as JSON and pass this processed data to the setLobby function.
Update the default value type in the LobbyContext to ILobby.
Within the useEffect hook, specify the dependencies of the fetch request. In this case, include the lobbyId dependency.
By making these adjustments, the lobby variable in the Scoreboard component should no longer be undefined and should receive the correct value.