Context with children(() => props.children) helper triggers an error
Hey! I've been trying to create a
Stepper
component in which I'd have StepperContext
with its API. however, somehow I need to control the displayed children, I found the children
helper but it doesn't work with context
https://playground.solidjs.com/anonymous/92dca985-17bc-4cbb-b2d8-d4b95fb33a33
am I missing something?Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
73 Replies
children
isn't necessary in that example, it's for more advanced use cases where you would otherwise be accessing props.children
more than once
the reason it errors is because children
is basically createMemo
- it eagerly evaluates the function inside it, which happens outside of the contextbut how to control the displayed child? I would like children to use context to control it
for example, if the
currentIndex
is 0
, then the first child will be shown
yeah the children
helper above the context provider executes all children outside of the contextyou don't need the children, but for
stepper.currentIndex()
to be reactive you have to wrap it in jsxSolid Playground
Quickly discover what the solid compiler will generate from your JSX template
in that case you would need
children
something like this
should the
currentIndex
be updated each second there? seems like nothing happensno it's a timeout, not an interval
oh
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
yeah got it!
thank you :)
you are welcome
you can think of
jsx
as if it is an effect
so just calling a signal inside the body of a component will not be reactive, but if you call it inside an effect/memo/jsx it will be
but if the goal is to display a certain html-element from its children, you maybe don't need context:
like brendonovich showedthe goal is to give the control of current index to
Step
s. so you can skip a step inside a step
for example inside a step...
instepcion
so the context should pass the setter and not the getter?
?
oh, typo
o wait lol now i make the same mistake again haha
because in this way you won't be able to access the current index in a step
it should wrap the children in the context ofcourse:
you can pass it in the context too, I wonder if you ever really need it
stepper.setCurrentIndex(currentIndex => currentIndex + 2)
oh that's cool
but you will know that better then me, I am still a bit unclear what a stepper-component does π
so you don't need a wrapper here
maybe
Stepper
is not the best name for this component, but I'd like to achieve such functionality where you don't really have "previous" and "next" buttons, so the steps itself control the index
maybe a function like setNext
and setPrevious
would be fine insteadmight be a bit less performant π€
why?
because
children()
will be called everytime props.children
gets called
but not sure tbh
what is the practical usecase for it: like a gallery of images?I guess this option is even more flexible because it'll be easier for you to separate steps from other elements (like stepper header or footer) so you don't need to filter the elements to get the steps
a form. for example, at first step you enter an email, then if a user with such email exists, it shows password, otherwise it requests verification code sent to the email
so if a user exists is a check at the first step, if this condition is true, then the verification step is skipped
or if a user enabled 2fa in their settings, there could also be a step for this
and you can skip it if user disabled it
gotcha
i see the big picture now
so using a stepper for this is kinda convenient
makes sens
I think one thing to keep in mind
is that
children(() => ...)
returns dom-elementsyeah
so you can't just filter it
like select children which are typeof
Step
so I said thisso will create 2 steps
oh really
just wrap in a div?
yes, because it returns 2 dom elements
yes, that's a solution, just something to be aware about
I'd make a generic
Step
component with aria attributes and a wrapper to avoid this
with this type of setup you can make it work
but a bit of an uglier api
yeah
so a wrapper like
Stepper.Steps
would be fine I guesssingular
Stepper.Step
u mean?no
for example..
so you can easily divide elements
in this case
<MyHeader/>
and <MyFooter/>
would be static?yes
like header would show the current index
and footer would have buttons to set next or previous steps
its flexible
that is possible
it's a possible feature
but it's a bit a different story
because
<MyHeader/>
is in the StepperContext
ye, I would probably keep it that everything inside
<Stepper/>
changes
but that's me
if you have a wrapper-component that returns a div
you can mark this div too
and actually filter on it inside the Stepper
-componentSolid Playground
Quickly discover what the solid compiler will generate from your JSX template
you'd get something like
or u could also add a symbol to the div and check for that inside
Stepper
I think there is a typo in that snippetthe type that
<Step/>
is before <MyHeader/>
?
it's possible to do if you don't have a wrapper
so it's not the best API tooSolid Playground
Quickly discover what the solid compiler will generate from your JSX template
I am talking about
</Stepper.Steps>
oh yes
that's interesting
but a bit more complicated
it allows you to filter and ignore children of
Stepper
that are not wrapped in a Step
, you could also give a warning and stuff like that: https://playground.solidjs.com/anonymous/a749fcfb-6b0d-4fd5-b651-4bb98cae516bSolid Playground
Quickly discover what the solid compiler will generate from your JSX template
I guess using a wrapper like
Stepper.Steps
is more straightforwardit doesn't solve the same problem tho
a child of
Stepper.Steps
could still return multiple html-elements
or could not be a Step
yeah I see the problem
it's a subtle difference with react
where in react a child of jsx is the jsx and not the html-element
because they have virtual dom
exactly
but ye I think you will figure it out!
lmk when you completed it, could be handy!
okay :)
thank you for the help! :)
@bigmistqke π, here's how I did it! https://playground.solidjs.com/anonymous/c6b2c3eb-8ece-4f3c-97a1-3ea31b7ea935
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
it's not perfect yet, but the component API is done
I'm wondering if there's a way to load steps lazily. for example, if the current step in a stepper UI is step 0, can I avoid loading the other steps (1 and 2) until they're actually needed?
my current implementation loads all steps upfront (try putting
onMount
in a StepperStep
with a console.log
)SolidJS
Solid is a purely reactive library. It was designed from the ground up with a reactive core. It's influenced by reactive principles developed by previous libraries.
it's possible, but then you will need to do some more hackery
if you look at the implementation of
<Switch><Match/></Switch>
you will see that it returns an object instead of a dom-element or function (in this case the props) https://github.com/solidjs/solid/blob/61dd1e88dd41175cb1e753121c8974b50e207dbf/packages/solid/src/render/flow.ts#L232GitHub
solid/packages/solid/src/render/flow.ts at 61dd1e88dd41175cb1e75312...
A declarative, efficient, and flexible JavaScript library for building user interfaces. - solidjs/solid
if I'd make it with
<Switch><Match/></Switch>
, then props.children
in StepperSteps
would always contain only the displayed element
and I wouldn't be able to get the steps length
i.e. stepper.setStepsCount(steps().length);
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
no i didn't mean to use Switch/Map, I meant how Switch/Map is able to lazily execute a JSX while it is already inside the markup
GitHub
[Help!!] Can I have both props from parent and props from children ...
Hello! I am trying to make my library to support SolidJs. But I am facing an obstacle and cannot find it. I checked all the relative articles and Q&A, but all of them are ended up suggesting a ...
most of the techniques I described here are also mentioned there
it's a very powerful pattern!
solid's jsx is very flexible, if you don't mind a type-assertion from time to time
I'm confused now.
children
is null here for some reason https://playground.solidjs.com/anonymous/c2cfed22-39ae-433b-9b47-d0257c4a81f5Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
yeah it's convenient
it's interesting
now you don't need to call
.toArray()
seems like that's an issue with @solid-primitives/refs
now it's not possible to filter it by symbol
I guess I need to wrap ref
creation it in a func f
and then assign symbol
to the f
or even better wrap it with createMemo
I guess thatβs because objects returned now instead of an array of JSX elementsI m afk! Going on holiday π but good luck with the component!
thanks! have a nice holiday! π
Here's been a similar discussion where I suggested to you a map or array on the parent node which provides the context where the children can add/remove themselves onMount/onCleanup and sort them by the Documentposition.
And you could then also provides the functions to skip a step etc.
https://discord.com/channels/722131463138705510/1258411547701542923/1258752653903794247
https://playground.solidjs.com/anonymous/edcd51d6-ee3f-4afb-a0d9-9847b4c1ef15
I think it's perfect now.
it loads the steps lazily, caches them and saves the reactivity as well
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
interesting workaround