S
SolidJSβ€’17mo ago
Zanoryt

How can I access a store from the parent context from inside of a nested context?

I am trying to access the WebsocketContext from inside of the DataStreamContext, in order to send out a websocket message when a DataStreamContext function is called. I can't seem to figure out the right way to do this. Provider structure:
<Html lang="en">
<Head>
<Title>Airframes</Title>
<Meta charset="utf-8" />
<Meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<Body>
<Suspense>
<ErrorBoundary>
<WebsocketProvider>
<DataStreamProvider>
<Routes>
<FileRoutes />
</Routes>
</DataStreamProvider>
</WebsocketProvider>
</ErrorBoundary>
</Suspense>
<Scripts />
</Body>
</Html>
<Html lang="en">
<Head>
<Title>Airframes</Title>
<Meta charset="utf-8" />
<Meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<Body>
<Suspense>
<ErrorBoundary>
<WebsocketProvider>
<DataStreamProvider>
<Routes>
<FileRoutes />
</Routes>
</DataStreamProvider>
</WebsocketProvider>
</ErrorBoundary>
</Suspense>
<Scripts />
</Body>
</Html>
22 Replies
foxpro 🐍
foxpro πŸβ€’17mo ago
Seems like you need to compose this two contexts into single one
thetarnav
thetarnavβ€’17mo ago
I can't seem to figure out the right way to do this.
You can access context in the same way you do in the routes. If it is below the provider it will be available, you just need a reference to WebsocketCtx
foxpro 🐍
foxpro πŸβ€’17mo ago
Seems he is asking how to access DataStream Context from Websocket Context, that is reverse order
thetarnav
thetarnavβ€’17mo ago
I am trying to access the WebsocketContext from inside of the DataStreamContext
πŸ€” if it’s the other way around then just reverse them πŸ€·β€β™‚οΈ
foxpro 🐍
foxpro πŸβ€’17mo ago
It's circular dependencies probably
Zanoryt
ZanorytOPβ€’17mo ago
I am trying to access the websocket from inside the datastream it builds on top of it Got it, so I just need to add a useContext inside of that context?
import { Socket, io } from "socket.io-client";
import { createContext, useContext } from "solid-js";
import { createStore } from "solid-js/store";

export const makeWebsocketContext = () => {
const [state, setState] = createStore({
socket: null as Socket | null,
connected: false,
error: null,
});
return [state, {
connect: () => {
console.log("WS: connecting");
const socket = io("http://localhost:3001", { transports: ["websocket"] });
setState('socket', socket);
state.socket?.connected && setState('connected', true);
},
disconnect: () => {
console.log("WS: disconnecting");
state.socket?.disconnect();
setState('socket', null);
setState('connected', false);
}
}] as const;
};
export type WebsocketContextType = ReturnType<typeof makeWebsocketContext>;
export const WebsocketContext = createContext<WebsocketContextType>();

export const WebsocketProvider = (props: any) => {
const websocket = makeWebsocketContext();

return (
<WebsocketContext.Provider value={websocket}>
{props.children}
</WebsocketContext.Provider>
);
}

export const useWebsocket = () => { return useContext(WebsocketContext); }
import { Socket, io } from "socket.io-client";
import { createContext, useContext } from "solid-js";
import { createStore } from "solid-js/store";

export const makeWebsocketContext = () => {
const [state, setState] = createStore({
socket: null as Socket | null,
connected: false,
error: null,
});
return [state, {
connect: () => {
console.log("WS: connecting");
const socket = io("http://localhost:3001", { transports: ["websocket"] });
setState('socket', socket);
state.socket?.connected && setState('connected', true);
},
disconnect: () => {
console.log("WS: disconnecting");
state.socket?.disconnect();
setState('socket', null);
setState('connected', false);
}
}] as const;
};
export type WebsocketContextType = ReturnType<typeof makeWebsocketContext>;
export const WebsocketContext = createContext<WebsocketContextType>();

export const WebsocketProvider = (props: any) => {
const websocket = makeWebsocketContext();

return (
<WebsocketContext.Provider value={websocket}>
{props.children}
</WebsocketContext.Provider>
);
}

export const useWebsocket = () => { return useContext(WebsocketContext); }
import { createContext, useContext } from "solid-js";
import { createStore } from "solid-js/store";

export const makeDataStreamContext = (props: any) => {
const [state, setState] = createStore({
favoriteStationIds: [15150280, 705556],
stationsToMonitor: [] as number[],
stations: [] as any[],
stationData: {} as any,
});
return [state, {
addStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', [...state.stationsToMonitor, stationId]);
console.log(props);
props.state.socket.emit("station:monitor:start", stationId);
},
removeStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', state.stationsToMonitor.filter((id: number) => id !== stationId));
}
}] as const;
}
export type DataStreamContextType = ReturnType<typeof makeDataStreamContext>;
export const DataStreamContext = createContext<DataStreamContextType>();

export const DataStreamProvider = (props: any) => {
const dataStream = makeDataStreamContext(props);

return (
<DataStreamContext.Provider value={dataStream}>
{props.children}
</DataStreamContext.Provider>
);
}

export const useDataStream = () => { return useContext(DataStreamContext); }
import { createContext, useContext } from "solid-js";
import { createStore } from "solid-js/store";

export const makeDataStreamContext = (props: any) => {
const [state, setState] = createStore({
favoriteStationIds: [15150280, 705556],
stationsToMonitor: [] as number[],
stations: [] as any[],
stationData: {} as any,
});
return [state, {
addStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', [...state.stationsToMonitor, stationId]);
console.log(props);
props.state.socket.emit("station:monitor:start", stationId);
},
removeStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', state.stationsToMonitor.filter((id: number) => id !== stationId));
}
}] as const;
}
export type DataStreamContextType = ReturnType<typeof makeDataStreamContext>;
export const DataStreamContext = createContext<DataStreamContextType>();

export const DataStreamProvider = (props: any) => {
const dataStream = makeDataStreamContext(props);

return (
<DataStreamContext.Provider value={dataStream}>
{props.children}
</DataStreamContext.Provider>
);
}

export const useDataStream = () => { return useContext(DataStreamContext); }
so instead of my incorrect props.state.socket.emit() here, I could access it via useContext() right?
REEEEE
REEEEEβ€’17mo ago
Yes
Zanoryt
ZanorytOPβ€’17mo ago
Ok, let me give that a shot. Hmmmm
import { createContext, useContext } from "solid-js";
import { createStore } from "solid-js/store";
import { useWebsocket } from "./Websocket";

export const makeDataStreamContext = () => {
const [_, websocket]: any = useWebsocket();
const [state, setState] = createStore({
favoriteStationIds: [15150280, 705556],
stationsToMonitor: [] as number[],
stations: [] as any[],
stationData: {} as any,
});
return [state, {
addStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', [...state.stationsToMonitor, stationId]);
websocket.socket.emit("station:monitor:start", stationId);
},
removeStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', state.stationsToMonitor.filter((id: number) => id !== stationId));
}
}] as const;
}
export type DataStreamContextType = ReturnType<typeof makeDataStreamContext>;
export const DataStreamContext = createContext<DataStreamContextType>();

export const DataStreamProvider = (props: any) => {
const dataStream = makeDataStreamContext();

return (
<DataStreamContext.Provider value={dataStream}>
{props.children}
</DataStreamContext.Provider>
);
}

export const useDataStream = () => { return useContext(DataStreamContext); }
import { createContext, useContext } from "solid-js";
import { createStore } from "solid-js/store";
import { useWebsocket } from "./Websocket";

export const makeDataStreamContext = () => {
const [_, websocket]: any = useWebsocket();
const [state, setState] = createStore({
favoriteStationIds: [15150280, 705556],
stationsToMonitor: [] as number[],
stations: [] as any[],
stationData: {} as any,
});
return [state, {
addStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', [...state.stationsToMonitor, stationId]);
websocket.socket.emit("station:monitor:start", stationId);
},
removeStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', state.stationsToMonitor.filter((id: number) => id !== stationId));
}
}] as const;
}
export type DataStreamContextType = ReturnType<typeof makeDataStreamContext>;
export const DataStreamContext = createContext<DataStreamContextType>();

export const DataStreamProvider = (props: any) => {
const dataStream = makeDataStreamContext();

return (
<DataStreamContext.Provider value={dataStream}>
{props.children}
</DataStreamContext.Provider>
);
}

export const useDataStream = () => { return useContext(DataStreamContext); }
websocket is undefined here inside of calling addStationToMonitor() and it doesn't seem to make sense to put the context into the state for this other context.
REEEEE
REEEEEβ€’17mo ago
you probably want
const [websocket]: any = useWebsocket();
const [websocket]: any = useWebsocket();
Zanoryt
ZanorytOPβ€’17mo ago
no i return two items
REEEEE
REEEEEβ€’17mo ago
since your websocket state is in the first index
Zanoryt
ZanorytOPβ€’17mo ago
yeah
REEEEE
REEEEEβ€’17mo ago
yes, but if you want to access socket.emit, that's in your state
REEEEE
REEEEEβ€’17mo ago
Zanoryt
ZanorytOPβ€’17mo ago
i have it in websocket (second item) ohh right, the second item is the functions Fantastic, that worked
REEEEE
REEEEEβ€’17mo ago
nice
Zanoryt
ZanorytOPβ€’17mo ago
One more issue. Trying to call socket.on() from inside of the DataStreamContext, but of course at time of initialization the socket does not yet exist. Is there some way to do this so that it can register those once the socket exists?
REEEEE
REEEEEβ€’17mo ago
you could use a createEffect
let initialized = false
createEffect(on(() => websocket.socket, (socket) => {
if(initialized) return;

if(socket){
initialized = true
socket.on(....)
}
}))
let initialized = false
createEffect(on(() => websocket.socket, (socket) => {
if(initialized) return;

if(socket){
initialized = true
socket.on(....)
}
}))
if you only want it to run once the socket is available you can have the initialized variable like I used there
Zanoryt
ZanorytOPβ€’17mo ago
oooooooh elegant let me give it a shot It works! Incredible.
import { createContext, createEffect, on, useContext } from "solid-js";
import { createStore } from "solid-js/store";
import { useWebsocket } from "./Websocket";

export const makeDataStreamContext = () => {
let intialized = false;
const [state, setState] = createStore({
favoriteStationIds: [15150280, 705556],
stationsToMonitor: [] as number[],
stations: [] as any[],
stationData: {} as any,
});

const [websocketState, _websocket]: any = useWebsocket();
createEffect(on(() => websocketState.socket, (socket: any) => {
if (intialized) return;

if (socket) {
intialized = true;
socket.on("station:monitor:data", (data: any) => {
console.log("DS: station:monitor:data", data);
});
socket.on("station:monitor:started", (data: any) => {
console.log("DS: station:monitor:started", data);
if (state.stations.filter((station) => station.id === data.station.id).length === 0) {
setState("stations", [...state.stations, { id: data.station.id, ident: data.station.ident, monitoring: true, messages: [] }]);
// if (stationIdSelected == data.stationId) setStore("stationSelected", data.station);
console.log(`DS: Browser ${data.browserId}: Started monitoring station ${data.station.id}`)
}
});
}
}));

return [state, {
addStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', [...state.stationsToMonitor, stationId]);
websocketState.socket.emit("station:monitor:start", stationId);
},
removeStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', state.stationsToMonitor.filter((id: number) => id !== stationId));
websocketState.socket.emit("station:monitor:stop", stationId);
}
}] as const;
}
export type DataStreamContextType = ReturnType<typeof makeDataStreamContext>;
export const DataStreamContext = createContext<DataStreamContextType>();

export const DataStreamProvider = (props: any) => {
const dataStream = makeDataStreamContext();

return (
<DataStreamContext.Provider value={dataStream}>
{props.children}
</DataStreamContext.Provider>
);
}

export const useDataStream = () => { return useContext(DataStreamContext); }
import { createContext, createEffect, on, useContext } from "solid-js";
import { createStore } from "solid-js/store";
import { useWebsocket } from "./Websocket";

export const makeDataStreamContext = () => {
let intialized = false;
const [state, setState] = createStore({
favoriteStationIds: [15150280, 705556],
stationsToMonitor: [] as number[],
stations: [] as any[],
stationData: {} as any,
});

const [websocketState, _websocket]: any = useWebsocket();
createEffect(on(() => websocketState.socket, (socket: any) => {
if (intialized) return;

if (socket) {
intialized = true;
socket.on("station:monitor:data", (data: any) => {
console.log("DS: station:monitor:data", data);
});
socket.on("station:monitor:started", (data: any) => {
console.log("DS: station:monitor:started", data);
if (state.stations.filter((station) => station.id === data.station.id).length === 0) {
setState("stations", [...state.stations, { id: data.station.id, ident: data.station.ident, monitoring: true, messages: [] }]);
// if (stationIdSelected == data.stationId) setStore("stationSelected", data.station);
console.log(`DS: Browser ${data.browserId}: Started monitoring station ${data.station.id}`)
}
});
}
}));

return [state, {
addStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', [...state.stationsToMonitor, stationId]);
websocketState.socket.emit("station:monitor:start", stationId);
},
removeStationToMonitor: (stationId: number) => {
setState('stationsToMonitor', state.stationsToMonitor.filter((id: number) => id !== stationId));
websocketState.socket.emit("station:monitor:stop", stationId);
}
}] as const;
}
export type DataStreamContextType = ReturnType<typeof makeDataStreamContext>;
export const DataStreamContext = createContext<DataStreamContextType>();

export const DataStreamProvider = (props: any) => {
const dataStream = makeDataStreamContext();

return (
<DataStreamContext.Provider value={dataStream}>
{props.children}
</DataStreamContext.Provider>
);
}

export const useDataStream = () => { return useContext(DataStreamContext); }
REEEEE
REEEEEβ€’17mo ago
nice!
Zanoryt
ZanorytOPβ€’17mo ago
This has really extracted out some functionality nicely. I'm impressed.
Zanoryt
ZanorytOPβ€’17mo ago
Looking sharp. Thanks for the help.
Want results from more Discord servers?
Add your server