S
SolidJS•16mo ago
tozz

Best way of passing props from Provider to Context

So I'm making a simple context with a Provider "wrapper" as is quite common to wrap functionality. I pass some values to it in JSX that should then be available when using the context.
interface DataGridContextValue {
readonly markets: Record<string, string>;
}

interface DataGridProviderProps {
children: JSX.Element;
markets: Record<string, string>;
}

export const DataGridContext = createContext<DataGridContextValue>();

export const DataGridProvider: Component<DataGridProviderProps> = (props) => {
// Implementation ...

const values = {
get markets() {
return props.markets;
},
// ... implementation API.
};

return <DataGridContext.Provider value={values}>{props.children}</DataGridContext.Provider>;
};
interface DataGridContextValue {
readonly markets: Record<string, string>;
}

interface DataGridProviderProps {
children: JSX.Element;
markets: Record<string, string>;
}

export const DataGridContext = createContext<DataGridContextValue>();

export const DataGridProvider: Component<DataGridProviderProps> = (props) => {
// Implementation ...

const values = {
get markets() {
return props.markets;
},
// ... implementation API.
};

return <DataGridContext.Provider value={values}>{props.children}</DataGridContext.Provider>;
};
This works well, but curious as to if there's a smarter way that I'm missing. Solid isn't wrapping reactivity for the value attribute, so I need to do something to keep reactivity. For usage of the provider it looks like this:
export const DataGrid: Component<DataGridProps> = () => {
const [markets] = createResource<Record<string, string>>(getMarkets);

return (
<DataGridProvider markets={markets()}>
...children
</DataGridProvider>
);
};
export const DataGrid: Component<DataGridProps> = () => {
const [markets] = createResource<Record<string, string>>(getMarkets);

return (
<DataGridProvider markets={markets()}>
...children
</DataGridProvider>
);
};
2 Replies
Martnart
Martnart•16mo ago
This sounds like a store scenario to me.
export const DataGridProvider: Component<DataGridProviderProps> = (props) => {
const [markets, setMarkets] = createStore(props.markets)

const values = {
markets,
setMarkets,
};
export const DataGridProvider: Component<DataGridProviderProps> = (props) => {
const [markets, setMarkets] = createStore(props.markets)

const values = {
markets,
setMarkets,
};
Only problem here is timing in terms of initial data. You could wrap the provider with a Show when={markets()} to make sure initial data has loaded, or you can add an effect that updates the store when props.markets changes
createEffect(
on(
() => props.markets,
setMarkets(props.markets)
)
)
createEffect(
on(
() => props.markets,
setMarkets(props.markets)
)
)
Is that kind of what you are looking for? With a store you retain reactivity wherever you use it. If you do not intend to alter the data in any way, I guess your way is absolutely fine, that way you don't have to duplicate the data. Depending on your specific setup, you could also move the resource directly into the provider to begin with so you don't have to worry about the props.
tozz
tozzOP•16mo ago
The data is read only so I don't need a store, and with many props using an effect would be very verbose setting everything up 🙂 Imagine having 5 more props like markets I don't like providers knowing about how and where data is located, I prefer them agnostic, otherwise moving the resources into the provider would work well (and I will do that for other things)
Want results from more Discord servers?
Add your server