S
SolidJS•3mo 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•3mo 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•3mo 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•3mo ago
Oh cool so I can just use content: () => {} to spawn a new window? Leeme try it
mdynnl
mdynnl•3mo ago
only doing this will work but I'd still recommend handling with Dynamic
Jason.json
Jason.jsonOP•3mo ago
oh my bad i forot to remove createRoot This sollution worked thanks man! šŸ‘
Jason.json
Jason.jsonOP•3mo ago
Ahhh now I can see why do you prefere <Dynamic component={...} {...props} /> over () => {}. It's much cleaner. šŸ˜„
mdynnl
mdynnl•3mo ago
hmm, I meant at the consuming side, which is inside For children callback in original example
Jason.json
Jason.jsonOP•3mo ago
Are there any performance differences between those two?
mdynnl
mdynnl•3mo 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•3mo ago
oh ok ok I read docs now I didn't know about it before Anyways thanks man
mdynnl
mdynnl•3mo ago
which part?
Jason.json
Jason.jsonOP•3mo ago
I mean I didn't know about <Dynamic> Cuz I've never used it before
mdynnl
mdynnl•3mo 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•3mo ago
šŸ˜†
bigmistqke
bigmistqke•3mo ago
Project looks cool!
Jason.json
Jason.jsonOP•3mo ago
Thanks! I use 7.css
Jason.json
Jason.jsonOP•3mo ago
boot screen
No description
Jason.json
Jason.jsonOP•3mo ago
and a login page
No description
Jason.json
Jason.jsonOP•3mo ago
I am trying to match frutiger aero style.
Jason.json
Jason.jsonOP•3mo ago
Our promised future šŸ˜†
Jason.json
Jason.jsonOP•3mo ago
TikTok
TikTok Ā· Jason.json34
Obejrzyj film użytkownika Jason.json34.
Jason.json
Jason.jsonOP•3mo 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•3mo ago
another look I am making an api to be able to extend it with api os calls
No description
Jason.json
Jason.jsonOP•3mo ago
example
No description
bigmistqke
bigmistqke•3mo ago
fuun!
Jason.json
Jason.jsonOP•3mo 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•3mo ago
And now after reboot we got:
No description
Jason.json
Jason.jsonOP•3mo ago
result:
No description
Jason.json
Jason.jsonOP•3mo ago
and by calling console.log(os.windows()) you can see all windows in os.
No description
Jason.json
Jason.jsonOP•3mo ago
package compiler
No description

Did you find this page helpful?