-
Notifications
You must be signed in to change notification settings - Fork 881
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
[labs/context] Request to allow custom ContextProvider in @provide decorator #3692
Comments
The @provide({ context: timerContext, provider: TimerProvider}); |
@rictic Could this be relooked at? I'm back to wishing something like this was built into Lit. I apologize for not including the full example and just showing what I thought the @provide syntax should be. I've updated my Lit Playground Example where I've modified the Heres a snippet from the playground of the very minor changes I'd like to see to allow overriding the default ContextProvider. It would have no changes to any current projects, but would allow more flexibility.
The end goal here is to have a provided object that is able to update itself. I do not see anyway this is possible without using a custom ContextProvider. The issue is if I want to bundle logic for controlling a timer, I cant just make a Timer class and provide that as that timer has no way of telling its consumer its updated. In the following example, the consumer will never update because the reference to the object isnt changing. The only way I see this is possible is bundling the timer logic into a ContextProvider.
|
@joezappie I think this is a misuse of ContextProvider. It's not meant to be a general solution for observable state, it's mean to allow passing values down a tree. What you're doing with What I would do is make an observable Timer class. There are several options including EventTarget, signals, observables, etc. We have a One of the most platform-centric and bare-bones way to be observable is to implement EventTarget. Then the consumer just has to listen to an event and update. I've made a decorator to make this more ergonomic before: const listeners = new WeakMap<Element, () => void>();
/**
* A property decorator that subscribes to an event on the property value and
* calls `requestUpdate` when the event fires.
*/
export const updateOnEvent = (eventName: string) => (target: ReactiveElement, propertyKey: string) => {
const descriptor = Object.getOwnPropertyDescriptor(target, propertyKey)!;
const {get, set} = descriptor;
const newDescriptor = {
...descriptor,
set(this: ReactiveElement, v: EventTarget) {
let listener = listeners.get(this);
if (listener === undefined) {
listeners.set(this, listener = () => this.requestUpdate());
}
const oldValue = get!.call(this);
oldValue?.removeEventListener?.(eventName, listener);
v?.addEventListener?.(eventName, listener);
return set!.call(this, v);
},
};
Object.defineProperty(target, propertyKey, newDescriptor);
}; I've update your playground top use this: https://lit.dev/playground/#gist=e3600ffc30ff9359404d4268c59d22a7 |
@justinfagnani Thank you for the fast reply! I think what you've shown is an excellent solution to what I'm looking to do. I agree, I always felt weird trying to turn the provider into basically a controller. I also like that components can subscribe to different events if only certain parts of the controller affect their display. Lots of flexibility there, awesome! |
Should this be an RFC?
Which package is this a feature request for?
Context (@lit-labs/context)
Description
I've been having a discussion in #3685 about how to deal with using an instance of a class as the value for the context value. Issue is, I want to encapsulate the logic for something, such as a timer that keeps track of the timer and status (stop, running, paused) without having to make the providing element know anything about it - aka it should be able to update its internal values itself.
@vdegenne informed me I could do this with a reactive controller. Since
ContextProvider
is already a reactive controller, I modified his example to extendContextProvider
, cutting out a bunch of code and allowing the timer to call setValue directly and without having to add another function to the providing element. Works pretty well:Playground Demo
Proposal
Issue is I cannot use
@provide()
directly as that forces creation of a ContextProvider. What I'd like to see is the ability to optionally pass in a provider class to use for that. I think this unlocks a lot of deeper possibilities with context providers if you can make your own custom provider class.Alternatives and Workarounds
Don't use the decorator and manually call it but that's no fun:
The text was updated successfully, but these errors were encountered: