Unable to provide context to children
I'm writing a dropdown component, so I decided to use a context to provide tools to the children. I have defined the context as an object with some setters and accessors to a set of signals and no matter what I do, I can't get it from the children components.
I'm using SolidJS + SolidStart
Here's some code snippets:
I have tried:
- Using props.children instead of children()
- Moving the context provider up
- Declaring the context as a store using createStore
I can't get Solid to provide the context and I don't really know the reason, every try throws the error :(
7 Replies
Are those snippets in the same module?
Otherwise it's not clear where
is getting
is forced to happen while the
DropdownContext
from.
That's why the general practice is to define both the provider (CounterProvider
) and the context specific hook (useCounter
) within the same module so that both can share the context value as a module global value.
Note: Context
as a module global isn't good enough if it is used during SSR as multiple requests within the same worker will share the same module (and by extension its globals). At that point it becomes necessary on the server side store the Context
in locals
of RequestEvent
to keep the Context
of each request isolated.
Finally, I haven't used children
a lot. But it seems to me that with:
You may force props.children
to be evaluated before the Context
is ready; i.e.is forced to happen while the
DropdownContext
still only contains undefined
.
So I'd start by isolating the provider and hook into their own module so that the provider can be imported at the root (at which time all of the context infrastructure should be initialized) and the hook can be imported separately by the nested component.The problem here is that the children are created early. Normally, props.children is a lazy access, so the children are created under the context provider boundary. In this case, you're eagerly accessing it in the solidChildren function (it's a wrapper around memo, which is eager). This means you're freaking the children outside the boundary.
https://docs.solidjs.com/reference/component-apis/children#children
Towards the bottom (though it sadly doesn't call out the implications for context)
An important aspect of the children helper is that it forces the children to be created and resolved, as it accesses props.children immediately.
Given:
I have tried: Using props.children instead of children()I suspect there may well be something else be going on in code that we aren't seeing …
It isn't clear where props.children was used. If it's in the same place as where the children are accessed / created in the above code, that would result in the same problem.
Or to restate the issue: the children helper does not change where the creation of children occurs, it's merely a helper to memoize so they're only created once. And the problem is that creating the children in the body of the component, above the jsx, is above the provider boundary.
In your example @peerreynders, children are created lazily in the jsx template. If you move the (nominally identical) access up above the jsx, it becomes eager and context will no longer work
Thank you guys for answering and sorry for my delay, had to clean the house followed by a power drop 🥲
Answering your messages, in order:
- Are those snippets in the same module? Yes, I'll be adjusting the code according to your description and make some tests, but if it's really necessary to declare context as locals for each request, then I don't really understood it's objective. The way I understood context was like an Angular component providing some value that is accessible in it's children, therefore the declaration of the context would just be some kind of identifier to the resource but I might be really wrong here.
- You may force props.children to be evaluated before the Context is ready I have tried using props.children instead of the children fn from solid, it had the same result
- So I'd start by isolating the provider and hook into their own module... I'll be doing that
- The problem here is that the children are created early... children() is only used in the snippet provided, and as I said, I have tried using props.children directly
- I suspect there may well be something else be going on in code that we aren't seeing … I'll take the business logic out of the component and provide you guys the hole file
------
As I was writing this answer, based on your suggestions, I was able to fix the problem. It's really a children fn problem. When I tried using
const DropdownContext = createContext<DropdownCtx>();
and both components are in the same module, only the usage part is outside the module.
- Context as a module global isn't good enough if it is used during SSR... I couldn't really find examples on context for SolidStart projets, props.children
I still had the children fn declaration at the beginning of the component and by removing that the problem was fixed!
I don't really know when to properly use the children fn, and I don't really remember where I've read that it was a good practice to use it on every component and please, if this is a wrong statement I would love to understand when it's a good thing to use it
Just for the sake of documentation, here's the fixed snippet:
Thank you guys for your help!but if it's really necessary to declare context as locals for each request.Generally context is only active on the client-side so there is nothing to worry about. It only becomes an issue once session specific information fed through context drives the initial server side render. At that point the context returned from
createContext
should be stored in a more isolated location than a module global that can be accessed by multiple concurrent requests on the server side.
https://github.com/peerreynders/solid-start-sse-chat/blob/d2b9070f956947c940dc2046abbbbf4bbcbd58e2/src/components/history-context/index.tsx#L380-L386
Clearly that wasn't your problem.GitHub
solid-start-sse-chat/src/components/history-context/index.tsx at d2...
Basic Chat demonstration with server-sent events (SSE) - peerreynders/solid-start-sse-chat
Oh, I see where this can cause some problems
Thank you very much for your help!