S
SolidJS•2y ago
Madaxen86

Context.Provider breaks reactivity

Need help with a simple Context Provider issue. Here's a little sample of the code:
const Accordion: ParentComponent<AccordionProps> = (props) => {
const contextValue = createMemo(() => ({ open: props.open, icon: icon(), animate: animate(), disabled: disabled(), })); createEffect(() => console.log("Accordion:", props.open, contextValue())); // 5. return return ( <AccordionContext.Provider value={contextValue()}> <div {...props} class={accordionClasses()}> {props.children} </div> </AccordionContext.Provider> ); }
const Accordion: ParentComponent<AccordionProps> = (props) => {
const contextValue = createMemo(() => ({ open: props.open, icon: icon(), animate: animate(), disabled: disabled(), })); createEffect(() => console.log("Accordion:", props.open, contextValue())); // 5. return return ( <AccordionContext.Provider value={contextValue()}> <div {...props} class={accordionClasses()}> {props.children} </div> </AccordionContext.Provider> ); }
ESLint throws "The reactive variable 'contextValue' should be used within JSX, a tracked scope (like createEffect), or inside an event handler function, or else changes will be ignored." And that's what happens. The ChildComponents which consume the context do not get updated. What do I need to do to makes this work. Thanks a bunch ahead already.
14 Replies
foolswisdom
foolswisdom•2y ago
Please use triple backticks to enclose your code so it is more easily readable 🙏
What do I need to do to makes this work.
You simply pass contextValue directly, don't call it. Calling it means you pass the value, not the signal reference Then, when you use the context, you need to call it to get the latest value It's a little unfortunate that context appears to behave differently from most components in solid With other components, you can rely on the compiler wrapping your props so that prop access is reactive, but because of the way context works, that doesn't help here (Also, don't confuse context here with context in react, context in react is a state mechanism - it rerenders when context changes. In solid it just passes values down to components when they first render) Hope that helps
Madaxen86
Madaxen86OP•2y ago
It still doesn't work. In the component which consumes the context with useContext...
Madaxen86
Madaxen86OP•2y ago
foolswisdom
foolswisdom•2y ago
When passing the value into the provider, you need to pass the signal (contextValue), not the value (contextValue()) What I wrote here
Then, when you use the context, you need to call it to get the latest value
refers to the place you get the context (as in, from a useContext() call) So
const value = useContext(AccordionContext)!;
value() // gives the current value
const value = useContext(AccordionContext)!;
value() // gives the current value
(Also, you're passing children to the div twice, you could remove the {props.children} and it will be passed through { ...props }, if I remember correctly) (that said, I'm a little surprised the linter knows you're passing into a provider, even though it's wrapped. Maybe it guesses based on the component + prop names?)
Madaxen86
Madaxen86OP•2y ago
I have adjusted to code in the parent to this
Madaxen86
Madaxen86OP•2y ago
and on the child I'm doing this:
foolswisdom
foolswisdom•2y ago
Try state().open Like here
Madaxen86
Madaxen86OP•2y ago
Yeah, that works :-). Typescript has thrown me off with "this expression is not callable"!?:
Madaxen86
Madaxen86OP•2y ago
foolswisdom
foolswisdom•2y ago
Yeah, you'll need to adjust the type you're using for the context It's probably the reason for the type error on value={} here as well Whatever type you're currently using for AccordionContextType, you should wrap it with the Accessor<> type from solid-js And if you have a default value from the context, you'll need to wrap that value in a function as well, so the types are consistent
Madaxen86
Madaxen86OP•2y ago
Yup. That was it. Thanks a bunch. Now it clicking. I didn't find that in the docs. Is there something you can recommend to check out when working with typescript and solid? I just found this and that threw me off: https://docs.solidjs.com/guides/foundations/typescript-for-solid#context
foolswisdom
foolswisdom•2y ago
Do you mind elaborating what there threw you off?
Madaxen86
Madaxen86OP•2y ago
Shouldn’t there be the Accessor wrapped around the Data type just like you have mentioned above? Like … createContext<Accessor<Data>>(()=>({count:0,name:””}))
foolswisdom
foolswisdom•2y ago
Only if you're actually passing an accessor You don't need to, if you're fine with the value being static I need to check the context page, if it's clear enough about reactivity and context
Want results from more Discord servers?
Add your server