-
Notifications
You must be signed in to change notification settings - Fork 15
Description
I'm using @lit/context and I often run into the limitation of wanting consumers to be able to update the provided value. Some basic use cases for this would be like a language switcher, dark/light theme toggle, or workspace selector (more advanced use cases later). In these, the component consuming the context should be able to modify the data and notify the provider so that other elements can update. Most other frameworks that have some form of context provide a mechanism for this.
I understand that context is not trying to become a state management tool. But I think a simple event to notify data change would greatly benefit frameworks building on top of it, while providing a much more elegant solution for simple things like the examples above and not requiring additional tools to keep necessary data in sync or greatly increasing the amount of code to implement it.
What I'm proposing is creating a ContextChangeEvent that consumers can emit with the new value so that the provider can update it. The solution I often use is implementing my own events that consumers emit and I have to add logic into the element providing it to update its value. I think that this is generic/boilerplate and that it should be built into context. Either elements can manually emit the event (providing a lot of possibilities for frameworks), or the ContextConsumer could trigger the event in the setter if previous value doesn't equal.
Functional Lit Examples
I have two examples that implement a ContextChangeEvent and the provider listens for events from it.
Table-View
In this Lit Playground Example, there is a user-list with two sub components table-view and column-picker. user-list provides a context for the data and another for which columns are visible. Here, I need my column-picker to update the context so that the table-view can rerender. I also want to support a filter-options component which would modify the query parameters used by the user-list but I left that out to keep it simple.
Timer Application
In this Lit Playground example, there is a Timer component that exposes Timer class instance. The timer class has logic for start/stop and the current timer count. There are two child components, one which displays the current time (only reads the context) and another which provides controls for the timer. I think more could be done to simplify this even more but I wanted an example that provides a class instance.
Alternatives Solutions
- As mentioned above, I've previously just manually created events but this creates a lot of boiler plate code.
- I've also experimented with providing an instance of
@lit-labs/signalsbut it increases the complexity of the solution and with it being in stage 1 ran into a few issues. - I also tried including setter functions in the value provided but I dislike this as the real value is nested and in order to get it to update, the object needs to be cloned with this setters. This becomes even more complex if your providing a class as it needs to clone the class anytime it changes the value.
@provide({ context: columnContext })
accessor columns = {
value: [1,2,3],
setColumns: (columns) => {
this.columns = {
...this.columns, // This feels hacky and if its a class instance you lose this reference
value: columns
};
}
}
I have a lot more thoughts on this topic, but I'm trying to keep it as simple as possible. I went through a lot of ideas while trying and this to me is the simplest and most natural.
Lit adheres to this protocol so they will only implement it if its in the standard. Linking the ongoing discussion there:
lit/lit#4908 (reply in thread)
edit - Lit is proposing the event name 'context-set-value'.