@inject
ts
inject<T>(key: ContextKey<T>): ValueObserver<T | undefined>Field sugar over $inject(). It asks once, at construction.
Usage
ts
@component({ name: 'Output' })
class Output extends Base {
@inject(CountContext)
count?: Signal<number>;
mounted() {
// The request may not have been answered yet.
return this.count?.subscribe((value) => {
this.$el.textContent = String(value);
});
}
}The field type includes undefined, because the request is asynchronous and the value lands when a provider answers.
When to use it, and when not
| Situation | Reach for |
|---|---|
| the value is there for the whole life of the instance | @inject |
| the consumer must be able to wait through several mount cycles | $inject() from mounted() |
| the answer is optional and there is a fallback | $injectSync() |
| the provider comes and goes | subscribeContext() |
@inject asks once, at construction. $inject() from mounted() is unmount-scoped: $unmount() cancels the pending request, and a new mount asks again. That difference is the whole reason both exist.
A plain field or an accessor
ts
@component({ name: 'Output' })
class Output extends Base {
@inject(CountContext) a?: Signal<number>;
@inject(CountContext) accessor b: Signal<number> | undefined;
}The function form
ts
class Output extends Base {
static config = { name: 'Output' };
async mounted() {
const count = await this.$inject(CountContext);
return count.subscribe((value) => {
this.$el.textContent = String(value);
});
}
}The await form has no undefined to handle, which is usually the better trade.