Confusing order of reactive events with context (useContext returns undefined) #2262
-
Hi folks, Frankly I'm confused about order of processing of reactive events in solid-js which, in theory, should not be the issue by design because JS engine is single-threaded. I keep struggling with it here and there. I'm trying to find root cause of following exception
Here is what I have right now SessionProvider where I create the context interface SessionData {
user: Nullable<User>
}
interface SessionContextValue {
context: SessionData;
setContext: SetStoreFunction<SessionData>;
}
export const SessionContext = createContext<SessionContextValue>();
const defaultSessionData: SessionData = {
user: undefined,
};
export function SessionProvider(props: { children: JSX.Element }) {
const [sessionData, setSessionData] = createStore<SessionData>(defaultSessionData)
const [isInitialized, setIsInitialized] = createSignal(false);
const initializeSession = async () => {
try {
const currentUser = await api.currentUser();
if (currentUser) {
setSessionData(produce(state => {
state.user = currentUser
}));
console.log(`SessionProvider: Logged in user is set to ${sessionData.user?.email}. Reloading dashboard state.`);
}
} finally {
setIsInitialized(true);
}
};
createComputed(async () => {
await initializeSession();
});
return <SessionContext.Provider value={{context: sessionData, setContext: setSessionData}}>
<Show when={isInitialized()}>{props.children}</Show>
</SessionContext.Provider>;
} DashboardContainer with standard UI components of my dashboard such as navigation bar, header, footer etc. export default function DashboardContainer(props: JSX.HTMLAttributes<HTMLElement>) {
const {context} = useContext(SessionContext);
return (
<AuthenticatedRoute>
LoggedIn User: {context.user?.email}
{props.children}
</AuthenticatedRoute>
);
} and finally AuthenticatedRoute where it all fails export default function AuthenticatedRoute(props: { children: JSX.Element }) {
const sessionContext = useContext(SessionContext);
const { context } = sessionContext;
const navigate = useNavigate();
onMount(async () => {
if (context.user == null) {
navigate(`/login?redirect=${encodeURIComponent(currentLocation())}`);
}
});
onError((ex) => {
console.error(ex);
if (ex instanceof ServiceError) {
if (ex.type == ErrorType.Authentication)
navigate(`/login?redirect=${encodeURIComponent(currentLocation())}`);
else {
// Handle other errors
console.error(ex);
}
});
return <ErrorBoundary fallback={(ex, reset) => {
console.error(ex);
try {
navigate(`/login?redirect=${encodeURIComponent(currentLocation())}`);
} catch (ex2) {
console.error(ex2);
}
return <div onClick={reset}>Error: {ex.toString()}</div>;
}
}>
<Suspense fallback={<div class="min-h-screen"><LoadingIcon/></div>}>
<Show when={context.user}>
{props.children}
</Show>
</Suspense>
</ErrorBoundary>
} Somehow AuthenticatedRoute returns undefined useContext() which I assume must be impossible because
This works if refresh the page but it doesn't if I ended up on login page after auth token has expired. Could you please explain what I'm missing ? Thank you. UPD: Would changing SessionProvider to return <Show when={isInitialized()}><SessionContext.Provider value={{context: sessionData, setContext: setSessionData}}>
{props.children}
</SessionContext.Provider></Show>; correct approach? Is there anything else I'm doing incorrectly? UPD2: Nope, didn't help :( |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
If it isn't even finding the context key which is ever present it's a lookup issue. Either something is iffy where SessionProvider is inserted or it's possible there is an error in our new fast lookup mechanism we added in 1.8. The first cause I can't see from the code examples given as we don't see where it is inserted. The second I would probably need a reproduction. If I were to debug this I'd be interested if Authenticated route could be created outside of the flow somewhere/created twice. |
Beta Was this translation helpful? Give feedback.
-
@ryansolid It turned out that my issues with order of initialization were coming from misunderstanding how JS' |
Beta Was this translation helpful? Give feedback.
If it isn't even finding the context key which is ever present it's a lookup issue. Either something is iffy where SessionProvider is inserted or it's possible there is an error in our new fast lookup mechanism we added in 1.8.
The first cause I can't see from the code examples given as we don't see where it is inserted. The second I would probably need a reproduction. If I were to debug this I'd be interested if Authenticated route could be created outside of the flow somewhere/created twice.