S
SolidJS8mo ago
robert_

Provider context isn't being executed on SSR website before child component?

Hi, I'm working on a website for work and I'm attempting to insert a provider as the parent of a child page in InertiaJS, Welcome.tsx
import { ErrorBoundary } from 'solid-js';
import Layout from '@/Layouts/SiteLayout';
import { PageProps } from '@/types/types';
// import { Container, Row, Col, Carousel, Button, Dropdown, ButtonGroup } from "solid-bootstrap";
import { withDialogProvider, Dialogs } from "@/Contexts/Dialog";
import ErrorPage from '@/Components/ErrorPage';

const Welcome = ({ color = "primary" }) => (
withDialogProvider(( onDispatch ) => (
<>
<p>Hello, world!</p>
</>
))
);

Welcome.layout = (page: PageProps) => {
console.log({ page });

return (
<ErrorBoundary fallback={ error => <ErrorPage error={error} />}>
<Layout props={page} page={<Welcome />} />
</ErrorBoundary>
);
};

export default Welcome;
import { ErrorBoundary } from 'solid-js';
import Layout from '@/Layouts/SiteLayout';
import { PageProps } from '@/types/types';
// import { Container, Row, Col, Carousel, Button, Dropdown, ButtonGroup } from "solid-bootstrap";
import { withDialogProvider, Dialogs } from "@/Contexts/Dialog";
import ErrorPage from '@/Components/ErrorPage';

const Welcome = ({ color = "primary" }) => (
withDialogProvider(( onDispatch ) => (
<>
<p>Hello, world!</p>
</>
))
);

Welcome.layout = (page: PageProps) => {
console.log({ page });

return (
<ErrorBoundary fallback={ error => <ErrorPage error={error} />}>
<Layout props={page} page={<Welcome />} />
</ErrorBoundary>
);
};

export default Welcome;
@/Layouts/SiteLayout.tsx
import { DefaultProps } from "@/types/types";
import { Navbar, Nav, NavDropdown, Container } from "solid-bootstrap";

import DialogProvider, { DialogType } from "@/Contexts/Dialog";

export default function SiteLayout({ children, props, page }: DefaultProps) {

const dispatcher = (dialog: DialogType, visible: boolean = true) => {
//
};

return (
<DialogProvider callback={dispatcher}>
<main class="header">
{children && children || page}
</main>
</DialogProvider>
);
}
import { DefaultProps } from "@/types/types";
import { Navbar, Nav, NavDropdown, Container } from "solid-bootstrap";

import DialogProvider, { DialogType } from "@/Contexts/Dialog";

export default function SiteLayout({ children, props, page }: DefaultProps) {

const dispatcher = (dialog: DialogType, visible: boolean = true) => {
//
};

return (
<DialogProvider callback={dispatcher}>
<main class="header">
{children && children || page}
</main>
</DialogProvider>
);
}
@/Contexts/Dialog.tsx
import { createContext, useContext } from 'solid-js';
import type { JSX, ParentProps, Context } from 'solid-js';
export type DIALOGS = { NEWMEMBER: 1, RXPRICING: 2, FINDMYRX: 3, ACTION2: 4, ACTION3: 5 };
export const Dialogs: DIALOGS = { NEWMEMBER: 1, RXPRICING: 2, FINDMYRX: 3, ACTION2: 4, ACTION3: 5 };
export type DialogType = DIALOGS[keyof DIALOGS] | string;
type DialogStateFn = (dialog: DialogType, visible?: boolean) => void;
type TChildFunc = (state: DialogStateFn) => JSX.Element;
let Dialog: Context<DialogStateFn> | undefined = undefined;

export default function Context ({ children, callback }: ParentProps<{ callback: DialogStateFn }>) {
if (Dialog === undefined) {
Dialog = createContext<DialogStateFn>(callback);
console.log("Initializing?");
}

return (
<Dialog.Provider value={callback}>
{children}
</Dialog.Provider>
);
};

export function useDialogCtx() {
if (Dialog === undefined) {
throw new Error("'Dialog' context provider not yet initialized.");
}
else return useContext(Dialog);
}

export const withDialogProvider = (callback: TChildFunc) => callback(useDialogCtx());
import { createContext, useContext } from 'solid-js';
import type { JSX, ParentProps, Context } from 'solid-js';
export type DIALOGS = { NEWMEMBER: 1, RXPRICING: 2, FINDMYRX: 3, ACTION2: 4, ACTION3: 5 };
export const Dialogs: DIALOGS = { NEWMEMBER: 1, RXPRICING: 2, FINDMYRX: 3, ACTION2: 4, ACTION3: 5 };
export type DialogType = DIALOGS[keyof DIALOGS] | string;
type DialogStateFn = (dialog: DialogType, visible?: boolean) => void;
type TChildFunc = (state: DialogStateFn) => JSX.Element;
let Dialog: Context<DialogStateFn> | undefined = undefined;

export default function Context ({ children, callback }: ParentProps<{ callback: DialogStateFn }>) {
if (Dialog === undefined) {
Dialog = createContext<DialogStateFn>(callback);
console.log("Initializing?");
}

return (
<Dialog.Provider value={callback}>
{children}
</Dialog.Provider>
);
};

export function useDialogCtx() {
if (Dialog === undefined) {
throw new Error("'Dialog' context provider not yet initialized.");
}
else return useContext(Dialog);
}

export const withDialogProvider = (callback: TChildFunc) => callback(useDialogCtx());
The error thrown is 'Dialog' context provider not yet initialized., which shouldn't be the case, since Layout wraps the DialogProvider at the top of the tree, is it because my Welcome component is being created first? How do I fix this? Thank you!
8 Replies
REEEEE
REEEEE8mo ago
Could be because you're destructuring props
robert_
robert_8mo ago
ooooh hmm
import { createContext, useContext } from 'solid-js';
import type { JSX, ParentProps, Context } from 'solid-js';

export type DIALOGS = { NEWMEMBER: 1, RXPRICING: 2, FINDMYRX: 3, ACTION2: 4, ACTION3: 5 };
export const Dialogs: DIALOGS = { NEWMEMBER: 1, RXPRICING: 2, FINDMYRX: 3, ACTION2: 4, ACTION3: 5 };

export type DialogType = DIALOGS[keyof DIALOGS] | string;
type DialogStateFn = (dialog: DialogType, visible?: boolean) => void;

type TChildFunc = (state: DialogStateFn) => JSX.Element;
let Dialog: Context<DialogStateFn> | undefined = undefined;

export default function Context (props: ParentProps<{ callback: DialogStateFn }>) {
if (Dialog === undefined) {
Dialog = createContext<DialogStateFn>(props.callback);
console.log("Initializing?");
}

return (
<Dialog.Provider value={props.callback}>
{props.children}
</Dialog.Provider>
);
};

export function useDialogCtx() {
if (Dialog === undefined) {
throw new Error("'Dialog' context provider not yet initialized.");
}
else return useContext(Dialog);
}

export const withDialogProvider = (callback: TChildFunc) => callback(useDialogCtx());
import { createContext, useContext } from 'solid-js';
import type { JSX, ParentProps, Context } from 'solid-js';

export type DIALOGS = { NEWMEMBER: 1, RXPRICING: 2, FINDMYRX: 3, ACTION2: 4, ACTION3: 5 };
export const Dialogs: DIALOGS = { NEWMEMBER: 1, RXPRICING: 2, FINDMYRX: 3, ACTION2: 4, ACTION3: 5 };

export type DialogType = DIALOGS[keyof DIALOGS] | string;
type DialogStateFn = (dialog: DialogType, visible?: boolean) => void;

type TChildFunc = (state: DialogStateFn) => JSX.Element;
let Dialog: Context<DialogStateFn> | undefined = undefined;

export default function Context (props: ParentProps<{ callback: DialogStateFn }>) {
if (Dialog === undefined) {
Dialog = createContext<DialogStateFn>(props.callback);
console.log("Initializing?");
}

return (
<Dialog.Provider value={props.callback}>
{props.children}
</Dialog.Provider>
);
};

export function useDialogCtx() {
if (Dialog === undefined) {
throw new Error("'Dialog' context provider not yet initialized.");
}
else return useContext(Dialog);
}

export const withDialogProvider = (callback: TChildFunc) => callback(useDialogCtx());
this still isn't working
REEEEE
REEEEE8mo ago
hard to tell what the issue is, but why not initialize the dialog context outside the Context component? The default value isn't really necessary
robert_
robert_8mo ago
I think I got it my Layout was wonky
Welcome.layout = (page: PageProps) => {
const Child = (...params: Array<any>) => page.children;

return (
<ErrorBoundary fallback={ error => <ErrorPage error={error} />}>
<Layout page={<Child {...page.props} />} />
</ErrorBoundary>
);
};
Welcome.layout = (page: PageProps) => {
const Child = (...params: Array<any>) => page.children;

return (
<ErrorBoundary fallback={ error => <ErrorPage error={error} />}>
<Layout page={<Child {...page.props} />} />
</ErrorBoundary>
);
};
that's what ended up fixing it I don't think that's going to work log-term though because I'm not forwarding my props to the component
REEEEE
REEEEE8mo ago
yeah seems like a weird solution is there a reason for Layout to take a page?
robert_
robert_8mo ago
just a different style, I'm still figuring out what I want my design patterns to be here
REEEEE
REEEEE8mo ago
gotcha
robert_
robert_8mo ago
but if that's where this design style takes me I think I'll pass on passing it as props hmmmm