S
SolidJSā€¢2mo ago
Jason.json

useContext returns undefined

Hi there! I am making a game launcher wich looks like an OS in frutiger aero style with Solid JS. I have a ContextProvider wrapping my whole app like so:
render(
() => (
<WindowManagerProvider>
<App />
</WindowManagerProvider>
),
document.getElementById("root")!
);
render(
() => (
<WindowManagerProvider>
<App />
</WindowManagerProvider>
),
document.getElementById("root")!
);
And i use the context inside a DraggableWindow.tsx here:
export default function DraggableWindow(props: DraggableWindowProps) {
const [position, setPosition] = createStore({ x: 100, y: 100 });
let ref: HTMLDivElement | undefined;

const context = useWindowManagerContext()!;
// rest of the code...
return (
// parent code
{props.children}
// parent code
);
}
export default function DraggableWindow(props: DraggableWindowProps) {
const [position, setPosition] = createStore({ x: 100, y: 100 });
let ref: HTMLDivElement | undefined;

const context = useWindowManagerContext()!;
// rest of the code...
return (
// parent code
{props.children}
// parent code
);
}
The context works inside the DraggableWindow, but when I try to use it in it's children it returns undefined. I use components to spawn a window with content.
No description
32 Replies
Jason.json
Jason.jsonOPā€¢2mo ago
Full context code:
interface WindowData {
id: string;
title: string;
content: JSX.Element;
class?: string;
}

interface WindowManagerContext {
openTeriminalWindow: () => void;
openWindow: (
title: string,
options: { content: JSX.Element; class?: string }
) => void;
dropWindow: (id: string) => void;
activeWindow: () => string;
setActiveWindow: (w: string) => void;
getAllWindows(): string[];
}

const WindowManager = createContext<WindowManagerContext>();

export function WindowManagerProvider(props: { children: JSX.Element }) {
const [activeWindow, setActiveWindow] = createSignal("");
const [windows, setWindows] = createStore<WindowData[]>([]);

const dropWindow = (id: string) => {
setWindows(windows.filter((w) => w.id !== id));
};

const openWindow = (
title: string,
options: { content: JSX.Element; class?: string }
) => {
const id = crypto.randomUUID();
setWindows([
...windows,
{ id, title, content: options.content, class: options.class },
]);
};

const openTeriminalWindow = () => {
createRoot(() => {
openWindow("Terminal", {
content: <TerminalWindow />,
class: "terminal-window",
});
});
};

return (
<WindowManager.Provider
value={{
openWindow,
openTeriminalWindow,
dropWindow,
setActiveWindow,
activeWindow,
getAllWindows: () => {
return Object.keys(windows);
},
}}
>
<>
<For each={windows}>
{(window) => (
<DraggableWindow
id={window.id}
title={window.title}
class={window.class}
>
{window.content}
</DraggableWindow>
)}
</For>
{props.children}
</>
</WindowManager.Provider>
);
}

export function useWindowManagerContext() {
return useContext(WindowManager);
}
interface WindowData {
id: string;
title: string;
content: JSX.Element;
class?: string;
}

interface WindowManagerContext {
openTeriminalWindow: () => void;
openWindow: (
title: string,
options: { content: JSX.Element; class?: string }
) => void;
dropWindow: (id: string) => void;
activeWindow: () => string;
setActiveWindow: (w: string) => void;
getAllWindows(): string[];
}

const WindowManager = createContext<WindowManagerContext>();

export function WindowManagerProvider(props: { children: JSX.Element }) {
const [activeWindow, setActiveWindow] = createSignal("");
const [windows, setWindows] = createStore<WindowData[]>([]);

const dropWindow = (id: string) => {
setWindows(windows.filter((w) => w.id !== id));
};

const openWindow = (
title: string,
options: { content: JSX.Element; class?: string }
) => {
const id = crypto.randomUUID();
setWindows([
...windows,
{ id, title, content: options.content, class: options.class },
]);
};

const openTeriminalWindow = () => {
createRoot(() => {
openWindow("Terminal", {
content: <TerminalWindow />,
class: "terminal-window",
});
});
};

return (
<WindowManager.Provider
value={{
openWindow,
openTeriminalWindow,
dropWindow,
setActiveWindow,
activeWindow,
getAllWindows: () => {
return Object.keys(windows);
},
}}
>
<>
<For each={windows}>
{(window) => (
<DraggableWindow
id={window.id}
title={window.title}
class={window.class}
>
{window.content}
</DraggableWindow>
)}
</For>
{props.children}
</>
</WindowManager.Provider>
);
}

export function useWindowManagerContext() {
return useContext(WindowManager);
}
mdynnl
mdynnlā€¢2mo ago
this is where the problem is
const openTeriminalWindow = () => {
createRoot(() => {
openWindow("Terminal", {
content: <TerminalWindow />,
class: "terminal-window",
});
});
};
const openTeriminalWindow = () => {
createRoot(() => {
openWindow("Terminal", {
content: <TerminalWindow />,
class: "terminal-window",
});
});
};
i believe the createRoot wrapping was to silence the computation created outside of a root warning but that's not its purpose. doing content: <TerminalWindow/> runs that component at that point inside the event handler which is outside of a root and context won't work because of that, you might work around it by using runWithOwner(owner, () => {...}) but that also means you need to know the owner ahead of time. instead, do content: () => <TerminalWindow/>, so that in a sense you're storing a component (components are essentially just functions in solid), then you can use <Dynamic component={...} {...props} /> at the consuming side
Jason.json
Jason.jsonOPā€¢2mo ago
Oh cool so I can just use content: () => {} to spawn a new window? Leeme try it
mdynnl
mdynnlā€¢2mo ago
only doing this will work but I'd still recommend handling with Dynamic
Jason.json
Jason.jsonOPā€¢2mo ago
oh my bad i forot to remove createRoot This sollution worked thanks man! šŸ‘
Jason.json
Jason.jsonOPā€¢2mo ago
Ahhh now I can see why do you prefere <Dynamic component={...} {...props} /> over () => {}. It's much cleaner. šŸ˜„
mdynnl
mdynnlā€¢2mo ago
hmm, I meant at the consuming side, which is inside For children callback in original example
Jason.json
Jason.jsonOPā€¢2mo ago
Are there any performance differences between those two?
mdynnl
mdynnlā€¢2mo ago
it's still content: () => <TerminalWindow /> or () => { ...; return .... } as long as it doesn't execute immediately Dynamic might have a little overhead you can also directly call it window.content()
Jason.json
Jason.jsonOPā€¢2mo ago
oh ok ok I read docs now I didn't know about it before Anyways thanks man
mdynnl
mdynnlā€¢2mo ago
which part?
Jason.json
Jason.jsonOPā€¢2mo ago
I mean I didn't know about <Dynamic> Cuz I've never used it before
mdynnl
mdynnlā€¢2mo ago
got it you can also pass tag name in component like component="div" ... very useful for dynamically constructing dynamic contents šŸ˜†
Jason.json
Jason.jsonOPā€¢2mo ago
šŸ˜†
bigmistqke
bigmistqkeā€¢2mo ago
Project looks cool!
Jason.json
Jason.jsonOPā€¢5w ago
Thanks! I use 7.css
Jason.json
Jason.jsonOPā€¢5w ago
boot screen
No description
Jason.json
Jason.jsonOPā€¢5w ago
and a login page
No description
Jason.json
Jason.jsonOPā€¢5w ago
I am trying to match frutiger aero style.
Jason.json
Jason.jsonOPā€¢5w ago
Our promised future šŸ˜†
Jason.json
Jason.jsonOPā€¢5w ago
TikTok
TikTok Ā· Jason.json34
Obejrzyj film użytkownika Jason.json34.
Jason.json
Jason.jsonOPā€¢5w ago
Here is a video wich I already made about it Idk if I can send it here šŸ˜Ø But discord limit is 8 MB only so... Here is how it looks like so far šŸ‘
Jason.json
Jason.jsonOPā€¢5w ago
another look I am making an api to be able to extend it with api os calls
No description
Jason.json
Jason.jsonOPā€¢5w ago
example
No description
bigmistqke
bigmistqkeā€¢5w ago
fuun!
Jason.json
Jason.jsonOPā€¢5w ago
Yup I am thinking about making it extendable by using os api like so You just write a default function wich accept os as argument On load it just provides the object To call example:
import type { OS } from "./types/os";

export default function main(os: OS) {
os.addContextMenu("my window", {
onClick: () =>
os.openWindow("my window", {
content: <p>Welcome in my window! :D</p>,
}),
});
}
import type { OS } from "./types/os";

export default function main(os: OS) {
os.addContextMenu("my window", {
onClick: () =>
os.openWindow("my window", {
content: <p>Welcome in my window! :D</p>,
}),
});
}
Jason.json
Jason.jsonOPā€¢5w ago
And now after reboot we got:
No description
Jason.json
Jason.jsonOPā€¢5w ago
result:
No description
Jason.json
Jason.jsonOPā€¢5w ago
and by calling console.log(os.windows()) you can see all windows in os.
No description
Jason.json
Jason.jsonOPā€¢5w ago
package compiler
No description

Did you find this page helpful?