Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Context] Support a ContextChangeEvent to allow consumers to update the provided value #70

Open
joezappie opened this issue Jan 31, 2025 · 1 comment

Comments

@joezappie
Copy link

joezappie commented Jan 31, 2025

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

  1. As mentioned above, I've previously just manually created events but this creates a lot of boiler plate code.
  2. I've also experimented with providing an instance of @lit-labs/signals but it increases the complexity of the solution and with it being in stage 1 ran into a few issues.
  3. 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'.

@joezappie joezappie changed the title Support a ContextChangeEvent to allow consumers to update the provided value [Context] Support a ContextChangeEvent to allow consumers to update the provided value Jan 31, 2025
@joezappie
Copy link
Author

One thing that came to mind is the ContextRequestEvent returns an unsubscribe callback. Maybe it would be cleaner to have a ContextGetSetterEvent which would return the set function which just provides a reference to provider.setValue and then the child element can cache that for later:

class ColumnPicker extends LitElement {

  @consume({ context: columnsContext, set: (set) => this.setColumns = set)
  accessor columns;
  
  onColumnUpdate() {
    const columns = this.getCheckedColumns();
    this.setColumns(columns, true);
  }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant