You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Firstly, thanks for the lit nanostore integration.
Here's what I'm wondering:
In the README all three of the examples (@useStores, withStores and StoreController) are being applied "directly" to the component. What I'm wondering about is composing a generic component with a particular bit of state more dynamically.
For example, let's say I have a design system with a bunch of components that define the look an behaviour of the components but not specifically what global state they will rely on. Then in particular instances I want to combine the generic component with a bit of state.
One way I could do this is to simply subclass (inheritance) or wrap (composition) the "stateless" design system components in a new component. That's workable, but does require naming a new webcomponent tag, which is a little clumsy. Ideally I'd just parameterise the generic component with the particular bit of state it will be backed by.
Example
Let's go through an example. First we need some global state:
exportconstglobalCount=atom<number>(0);
Then let's have our generic design system counter display:
We actually wanted write <ds-counter . count${globalCount}>, but had to make do with <ds-counter-with-global-count>.
Alternative dynamic approach
I have found one approach that does (seem to) work. We add a bit more to the generic "stateless" design system component, namely we have a StoreController field and then in firstUpdated we create a new controller which will make the component reactive.
This is exactly what we wanted to write, is reactive (and in such a way that only this component will rerender) and doesn't require defining a separate component name.
My questions are:
Does this approach make sense?
Is there some nicer way to achieve the same thing (the more dynamic "binding")? It feels a little clumsy as written.
Any other approaches?
An obvious one is the toplevel App to @useStores all of the app state and pass down any <store>.get(). This will all work as expected but will cause unwanted rendering of in-between components?
Maybe something with @lit/context (but I haven't played with that so I don't know)
The text was updated successfully, but these errors were encountered:
Thanks for bringing up this scenario and sharing your exploration.
Passing Stores as props from a parent to a child is not actually something I have come across before. For myself I would let the property of ds-counter be a number rather than a store containing a number, then the parent would need to unwrap the store and pass the value down instead. But I can understand if you are doing something like a design system that uses Nanostores for global state it could make sense to pass a store directly.
I agree that none of the approaches you found seems ideal. And I was not able to produce anything more clean than what you have there. I am not a big fan of subclassing in user code like the first example, so personally I would shy away from that. I also feel like it doesn't quite achieve the goal since the user of the component can't dynamically pass a store. And I think the other example will actually not work if the store is changed during the lifetime of the component. Instead we would need something like this:
@customElement("ds-counter")exportclassDesignSystemCounterextendsLitElement{
@property({type: Object})count: Store<number>=atom(0);protectedcontroller: StoreController<number>|null=null;protectedupdated(changedProperties: PropertyValues<this>){if(changedProperties.has("count")){if(this.controller){this.controller.unsubscribe?.();// At the moment, unsubscribe() is not publicly exposed.}this.controller=newStoreController(this,this.count);}}protectedrender(){returnhtml`${this.count.get()}`;}}
Now this just makes it even more clumsy, but it should work even when changing out the store.
I have not used @lit/context so I can't tell if it would help here.
If you have a suggestion for how we could add to the API to accomodate this I'd be happy to do some exploration. Otherwise I think we should leave this issue open so others can chime in if they want this.
Firstly, thanks for the lit nanostore integration.
Here's what I'm wondering:
In the README all three of the examples (
@useStores
,withStores
andStoreController
) are being applied "directly" to the component. What I'm wondering about is composing a generic component with a particular bit of state more dynamically.For example, let's say I have a design system with a bunch of components that define the look an behaviour of the components but not specifically what global state they will rely on. Then in particular instances I want to combine the generic component with a bit of state.
One way I could do this is to simply subclass (inheritance) or wrap (composition) the "stateless" design system components in a new component. That's workable, but does require naming a new webcomponent tag, which is a little clumsy. Ideally I'd just parameterise the generic component with the particular bit of state it will be backed by.
Example
Let's go through an example. First we need some global state:
Then let's have our generic design system counter display:
Note: we haven't said which bit of state this depends on.
As state before, we could use a subclassing approach to "bind" to our desired global state for the particular instance of the component:
Then our app may be:
We actually wanted write
<ds-counter . count${globalCount}>
, but had to make do with<ds-counter-with-global-count>
.Alternative dynamic approach
I have found one approach that does (seem to) work. We add a bit more to the generic "stateless" design system component, namely we have a
StoreController
field and then infirstUpdated
we create a new controller which will make the component reactive.Our
App
definition then becomes:This is exactly what we wanted to write, is reactive (and in such a way that only this component will rerender) and doesn't require defining a separate component name.
My questions are:
App
to@useStores
all of the app state and pass down any<store>.get()
. This will all work as expected but will cause unwanted rendering of in-between components?@lit/context
(but I haven't played with that so I don't know)The text was updated successfully, but these errors were encountered: