-
-
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
invokeHelper
#626
invokeHelper
#626
Conversation
Would it be possible to implement |
It would not. There is no way to lookup a helper manager instance using public APIs, and the hooks on helper managers are meant to be wrapped by the VM directly. For instance, This is the minimum API we can expose in order to invoke a helper in the same way as it would be if done by the VM, which is the goal. |
Helpers work, but like components they require us to move some of our logic | ||
into the template, even if that isn't really necessary: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow this part. What is the unnecessary part in the template? Just the invocation of the helper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, exactly. You can't refer to the value of the helper in JS anymore, so any computed properties you have that may rely on the value of the helper now need to be in the template, any other business logic now needs to be moved into the template, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I don't see that as unnecessary 🤔
Either way (either with this RFC or with templates) you have to invoke the helper. The only question is where that invocation actually is.
reactive code and patterns, and reuse them transparently. This will make helpers | ||
the new reactive atom of the system - the reactive equivalent of a "function" in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, I don't think this actually changes the atom, it just makes helpers an equal peer to components. Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Helpers are already a peer. The issues is neither helpers nor components can be used in JS-only. This API makes helpers better than components for many use cases, and makes them usable in many more places, so I would say they are the reactive atom now. Especially considering Glimmer components have no lifecycle hooks, so they can't even do the same things anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but the prose here infers that we should now always decompose components into helpers because "they are the smallest atom", which I don't think is correct either.
We discussed this in today’s core team meeting, and think it is ready to move into final comment period. 🥖🥳🕺 |
Great feature, I definitely would use this. Just one quick question, not sure if I'm missing something but in your example import Component from '@glimmer/component';
import Helper from '@ember/component/helper';
import { invokeHelper } from '@ember/helper';
class PlusOne extends Helper {
compute([num]) {
return number + 1;
}
}
export default class PlusOne extends Component {
plusOne = invokeHelper(this, RemoteData, () => {
return {
positional: [this.args.number],
};
});
} You meant import Component from '@glimmer/component';
import Helper from '@ember/component/helper';
import { invokeHelper } from '@ember/helper';
class PlusOneHelper extends Helper {
compute([num]) {
return number + 1;
}
}
export default class PlusOne extends Component {
plusOne = invokeHelper(this, PlusOneHelper, () => {
return {
positional: [this.args.number],
};
});
} |
I'm excited for this to land -- definitely will be useful for us. The part I'm confused by is the Not knowing the limitations that might have led to this design choice, I would prefer if the types look more like this: -interface TemplateArgs {
- positional?: unknown[],
- named?: Record<string, unknown>
-}
+type TemplateArgs = unknown[] | Record<string, unknown>
type HelperDefinition<T = unknown> = object;
function invokeHelper<T = unknown>(
parentDestroyable: object,
definition: HelperDefinition<T>,
computeArgs?: (context: object) => TemplateArgs
): Cache<T>; |
A helper could use both positional and named arguments at the same time. E.g. |
@scottmessinger @jelhan's explanation is correct, it is not an either-or API, both can be passed in at the same time. This API is also meant to be a primitive API - the idea is that higher level APIs will be written on top of this to provide easier to use, more ergonomic DX. Those APIs could add the logic you're describing for instance. |
We discussed this in Friday's core team meeting, and think it is ready to land. Thank you to @pzuraq and all of y'all that helped hone this proposal! 🚁 🐎 🚗 |
Note: OP needs an update to the final version of the RFC! |
I wonder if the RFC should mention/clarify that this doesn't mean that helpers now replace utils (or perhaps it does) - in many cases a helper can also be useful as a util for re-use in some JS. At the moment it makes sense to write the helper as a util and then call the util from the helper:
export default function myReusableUtil(someService, thingy) {
return someService.modifyThingy(thingy)
}
import Helper from '@ember/component/helper';
import myReusableUtil from '../utils/helper';
import { inject as service } from '@ember/service';
export default class MyReusableUtilHelper extends Helper {
@service someService;
compute([thingy]) {
return myReusableUtil(this.someService, thingy);
}
} However this PR could encourage the perspective that most/all utils should just always be helpers, since helpers can be easily invoked in JS or templates - so why bother with utils at all after this? |
Adds Helper Manager and `invokeHelper` APIs from emberjs/rfcs#625 and emberjs/rfcs#626.
Rendered