-
-
Notifications
You must be signed in to change notification settings - Fork 408
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
Add context-like solution to avoid props drilling #775
Comments
you're good! no worries
There are a couple similar implementations floating around in library form:
I think @pzuraq was maybe looking at implementing something natively? but I don't recall atm.
There are a few ways:
more information on services here: https://guides.emberjs.com/release/services/
More information on yielding data here: https://guides.emberjs.com/release/components/block-content/#toc_block-parameters
export default class MyComponent extends Component {
lotsOfData = {
...
}
} <Top @data={{this.lotsOfData]}>
<AComponent>
<DeepComponent @data={{this.lotsOfData}}>
<InternalToDeepComponent @data={{this.lotsOfData}} />
</DeepComponent>
</AComponent>
</Top> I know this doesn't solve every problem contexts are use for, but these patterns due help mitigate prop-drilling, specifically. For things that we don't yet have good answers for:
|
@NullVoxPopuli thank you for the quick and detailed answer! <div>Panel</div>
<Photo @photo={{this.photo}} />
<MainInfo @info={{this.info}} />
<MainSection @section={{this.section}}/> each of children has other components mixed with the common markup (not simple to transform it via provider-like way) etc etc. Technically it's not a big problem to transform it to <div>Panel</div>
<Photo @photo={{this.photo}} @context={{this.context}} />
<MainInfo @info={{this.info}} @context={{this.context}} />
<MainSection @section={{this.section}} @context={{this.context}} /> I really enjoy your route based approach and would like to see the same with I think that's why it would be nice to have native support for such functionality. |
while true, my addon doesn't require those (I think?) it's been a while
I agree Though, I think a discussion missing from this conversation is public vs private api for the consumer of tthe components. Imo, contexts are a private detail that the consumer of your components shouldn't have to know about. If any component requires an external context provider to be added, that's a leakage of responsibility, and should be avoided (because it means the user can screw it up, and we want to protect them). that said, It is common for component authors to jump through whatever hoops they need to in order to make the public api as nice as possible. (cause it's worth it!) |
That's true, it doesn't. I meant my case when it's needed to create a service that's private to a component, not to a route (and have N instances for N components under 1 route).
I agree. From this it does not look good. Yeah, although it violates some principles, nevertheless, it would be useful. In case of emergency interfaces and strict assertion can be added to avoid incorrect usage of public api: export default class GlimmerComponent<Args extends {} = {}, Context extends {} = {}> extends _GlimmerComponent<Args, Context> { throw new Error('You must pass a context....') |
Hey there, so I would also be highly interested in this. My use case is not prop drilling, but what @NullVoxPopuli already touched above: declaratively rendering to a DOM-less world (here WebGL, but could also be a 2D canvas context or some maps API). What you need there is managing a hierarchy of nodes within a large tree (e.g. a "Scene"). This is covered in more detail in my previous RFC issue #597 (the first part of "Managing hierarchies"). That would be possible to support either via an API that exposes the parent component instance (e.g. through some opt-in component manager capability, so that not every component has this (abusable) feature), or a context API. If you have one of these, you could basically based on that implement the other one as well. But a context API would be perfectly sufficient for this use case. (e.g. the recently released So whatever the underlying primitive should be, I would be highly interested in dedicating time to move this forward (e.g. draft a RFC). But would certainly need guidance on the technical direction (no in-depth GlimmerVM knowledge). For example instead of designing a full-fledged context API, we could maybe also - as we have done before - only expose a low-level primitive (aka manager) that can be used to implement this in a user-land addon (leaving room for more experimentation). Not that I have that much time, but the lack of this features is just a - sorry - PITA and makes me loose time (I use an ugly AST template transform to workaround the limitations, but that comes with its own set of problems). Also quite unfortunate that it seems Ember is the only major framework that does not properly support the use case of declarative 3D rendering, while others provably do (e.g. For the record, I found this related discussion on Discord between @pzuraq and @GCheung55 (hope I picked the right GH handle?). @pzuraq as we had some chats about this topic before, would you be able and willing to be that RFC "champion"? Or anyone else here? |
I'm closing this due to inactivity. This doesn't mean that the idea presented here is invalid, but that, unfortunately, nobody has taken the effort to spearhead it and bring it to completion. Please feel free to advocate for it if you believe that this is still worth pursuing. Thanks! |
Hi! I wonder if anyone put any more thought into potentially adding a context-like API to Ember recently? I recently came across https://github.com/alexlafroscia/ember-context, but the caveats listed in the addon probably don't make it a viable option for us in production. So I started looking into Glimmer internals, and found the DebugRenderTree, which - I believe - is used only for Ember Inspector.
I created a small proof of concept over on this branch: https://github.com/customerio/glimmer-vm/tree/provide-consume-context (see the diff here), where I built a context API backed by a It's sort of a very simplified version of the For testing purposes, my context provider component class is export default class ContextProvider extends Component {
static _isProvideConsumeContextProvider = true;
get id() {
// A string id to use for retrieving the provider's value in other components
return this.args.id;
}
get value() {
// The value to be associated with this provider
return this.args.value;
}
} {{yield}} Then I built a Consumer component, which looks like this export default class ContextConsumer extends Component {
get contextValue() {
let renderer = getOwner(this).lookup('renderer:-dom');
let provideConsumeContextContainer = renderer._runtime.env.provideConsumeContextContainer;
// Retrieve the "contexts object" that was attached to the instance of this component
let contexts = provideConsumeContextContainer.contexts.get(this);
// "contextId" is the same string used in a ContextProvider. This returns the actual instance of the rendered Provider component
let providerComponentInstance = contexts[this.args.contextId];
// return the value from the provider
return providerComponentInstance?.value;
}
} This abuses some Ember internal APIs, but overall the approach seems to work. The core of contexts is really passing all provider values down the component tree. Could we introduce an API like this into Glimmer/Ember proper? Is there anything obviously wrong with this approach? I admit I'm not at all familiar with the intricacies of how Glimmer renders things, so I wouldn't be surprised if this doesn't work in some scenarios. And a note on motivation: in the Ember world, contextual components and services are usually how we handle context-like scenarios. However, this doesn't work well when we want to expose certain states down a whole component tree without having to pass the state as argument through all layers. For example, we're building a new design system/component library internally, and context would allow us to make more magic happen within that library. Some of our components accept a background color property - with context, we can have all child components automatically switch to the correct text color or background color to match the "context" they're in. Again as an example, an "error" alert with a red background would be a context provider, and all button components inside it would also choose the appropriate error/red state appearance to match. Locally scoped CSS variables can do some of that, but for more complex components we'd need too many special variables to make it work. A button component needs its text color, background color, border color AND all the attached hover/focus/active states changed, depending on what sort of background it's on. |
I think it's worth pursuing! Can you open an rfc pr? No need to get too detailed initially, you could start with copying your comment content in to the new file in the pr! |
@NullVoxPopuli RFC PR here: #975 Thanks for the encouragement! |
Good day to all!
Is it possible from performance perspective and workload to provide support for
React/Angularcontext-like functionality?For more than 2 years of work with Ember I have come across an urgent need for this functionality several times (mostly large components with different configurations).
I know there are some solutions (e.g. ember-context), but some of them don't have full functionality or don't work with Glimmer components.
Ideally I would like to see something similar to:
where in
deep-component
I can usethis.context
.Could someone share any information about this functionality, what were the proposals?
As well as could you tell how you deal with this props drilling effect?
I am sure that similar questions have already been asked, sorry for that.
The text was updated successfully, but these errors were encountered: