inject
Reads the value provided with provide by the nearest ancestor and fails if none provided it.
Se autoimporta en las aplicaciones del framework.
import { inject } from "@meekojs/meeko";inject(key) walks up the active component's roots (the component itself, its parent, its parent's parent…) and returns the value from the first one that provided key with provide. If none did, it throws an error with the key's description instead of returning undefined: a missing context is a structural failure, not a case the template should handle.
It is exported from @meekojs/meeko and auto-imported in framework applications.
Usage#
<!-- app/components/ThemeBadge.meeko -->
<script lang="ts">
import { themeKey } from "../composables/theme";
const theme = inject(themeKey); // Signal<"light" | "dark">
</script>
<template><span class="badge" bind:data-theme="theme.value">Theme {theme.value}</span></template>Because the layout provided a signal, the badge updates when the theme changes.
Type#
function inject<T>(key: ContextKey<T>): Ttype ContextKey<T> = symbol & {
readonly __meekoValue?: (value: T) => T
}Parameters#
| Parameter | Type | Default | Description |
|---|---|---|---|
key |
ContextKey<T> |
required | Key created with createContext. The same instance used by provide, not another with the same description. |
Return value#
The value T from the nearest provider. If no ancestor provided the key, it throws Error: Missing Meeko context: <descripción> (without a description, Missing Meeko context).
Examples#
A composable that wraps inject#
Export a named function instead of the key: its users do not need to know there is a context.
// app/composables/session.ts
import { createContext, inject } from "@meekojs/meeko";
import type { ReadonlySignal } from "@meekojs/meeko";
export const sessionKey = createContext<ReadonlySignal<{ name: string } | null>>("session");
export const useSessionUser = (): ReadonlySignal<{ name: string } | null> => inject(sessionKey);<script lang="ts">
const user = useSessionUser();
</script>
<template><p if:when="user.value">Hello, {user.value.name}</p></template>The nearest provider wins#
import { createContext, createRoot, inject, provide } from "@meekojs/meeko";
const sizeKey = createContext<"sm" | "md">("size");
const size = createRoot(() => {
provide(sizeKey, "md");
return createRoot(() => {
provide(sizeKey, "sm");
return createRoot(() => inject(sizeKey));
});
});
// size === "sm"An optional context#
inject has no default value. If a component must work with and without a provider, provide the default value in app/app.meeko or handle the case with try:
import { inject } from "@meekojs/meeko";
import type { ContextKey } from "@meekojs/meeko";
export function injectOr<T>(key: ContextKey<T>, fallback: T): T {
try { return inject(key); }
catch { return fallback; }
}Common mistakes#
A component outside the provider#
<!-- app/pages/index.meeko: the layout does not call provide(themeKey, …) -->
<ThemeBadge />Rendering fails with Error: Missing Meeko context: theme. Provide the value in an ancestor of all its readers, such as the layout or app/app.meeko:
<!-- app/layouts/default.meeko -->
<script lang="ts">
import { themeKey } from "../composables/theme";
provide(themeKey, signal<"light" | "dark">("light"));
</script>Calling it in a handler or after an await#
inject searches from the active root, which only exists while the component script runs.
async function save(): Promise<void> {
await persist();
inject(toastsKey).show("Saved");
}Outside the script there is no active root, and it throws Missing Meeko context: toasts. Call inject at the top level of the script and keep the value:
const toasts = inject(toastsKey);
async function save(): Promise<void> {
await persist();
toasts.show("Saved");
}Reading the value instead of the signal#
const theme = inject(themeKey).value;theme is the text at that moment: the template does not update when the theme changes. Keep the signal and read .value where you use it:
const theme = inject(themeKey);
// <span>{theme.value}</span>Notes#
- Server and browser. It works the same in both, with values provided by ancestors in that same execution.
- Where to call it. At the top level of the script or in a composable it calls. The content of a snippet or a
<MeekoTeleport>sees the contexts of the component that declares it. - Siblings. Only ancestors are searched: a sibling that provided the key does not count.
- Meeko context.
useState,useRoute,useNavigationand other framework composables rely on this same mechanism. That is whyuseStateoutside an application throwsMissing Meeko context: Meeko framework state.