Provides Vue 3 Composition API compatibility for Vue 2 applications with reactive state management and lifecycle hooks.
—
Provide/inject system for passing data down the component tree without explicit prop drilling. This enables ancestor components to serve as dependency providers for all their descendants, regardless of how deep the component hierarchy is.
Provides a value that can be injected by descendant components. Values are provided with a key and can be accessed by any descendant component.
/**
* Provides a value for descendant components to inject
* @param key - Injection key (string or symbol)
* @param value - Value to provide
*/
function provide<T>(key: InjectionKey<T> | string, value: T): void;
interface InjectionKey<T> extends Symbol {}Usage Examples:
import { provide, reactive } from "@vue/composition-api";
// String-based key
export default {
setup() {
const theme = reactive({
primaryColor: "#007bff",
secondaryColor: "#6c757d",
darkMode: false,
});
provide("theme", theme);
const userSettings = reactive({
language: "en",
timezone: "UTC",
});
provide("userSettings", userSettings);
return {};
},
};
// Symbol-based key for type safety
import { InjectionKey } from "@vue/composition-api";
interface Theme {
primaryColor: string;
secondaryColor: string;
darkMode: boolean;
}
const ThemeKey: InjectionKey<Theme> = Symbol("theme");
export default {
setup() {
const theme = reactive({
primaryColor: "#007bff",
secondaryColor: "#6c757d",
darkMode: false,
});
provide(ThemeKey, theme);
return {};
},
};Injects a value provided by an ancestor component. Supports default values and type-safe injection keys.
/**
* Injects a value provided by an ancestor component
* @param key - Injection key to look for
* @returns Injected value or undefined if not found
*/
function inject<T>(key: InjectionKey<T> | string): T | undefined;
/**
* Injects a value with a default fallback
* @param key - Injection key to look for
* @param defaultValue - Default value if injection key not found
* @returns Injected value or default value
*/
function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T;
/**
* Injects a value with a default factory function
* @param key - Injection key to look for
* @param defaultValue - Factory function for default value
* @param treatDefaultAsFactory - Whether to treat default as factory (true by default)
* @returns Injected value or result of default factory
*/
function inject<T>(
key: InjectionKey<T> | string,
defaultValue: () => T,
treatDefaultAsFactory: boolean
): T;Usage Examples:
import { inject } from "@vue/composition-api";
// Basic injection
export default {
setup() {
const theme = inject("theme");
if (theme) {
console.log("Current theme:", theme);
}
return {
theme,
};
},
};
// Injection with default value
export default {
setup() {
const theme = inject("theme", {
primaryColor: "#000000",
secondaryColor: "#ffffff",
darkMode: false,
});
return {
theme,
};
},
};
// Type-safe injection with symbol key
import { InjectionKey, inject } from "@vue/composition-api";
interface Theme {
primaryColor: string;
secondaryColor: string;
darkMode: boolean;
}
const ThemeKey: InjectionKey<Theme> = Symbol("theme");
export default {
setup() {
const theme = inject(ThemeKey); // TypeScript knows this is Theme | undefined
const safeTheme = inject(ThemeKey, {
primaryColor: "#000000",
secondaryColor: "#ffffff",
darkMode: false,
}); // TypeScript knows this is Theme
return {
theme,
safeTheme,
};
},
};Complex patterns for dependency injection including reactive providers, service injection, and contextual data.
Reactive Provider Pattern:
import { provide, reactive, readonly } from "@vue/composition-api";
// Provider component
export default {
setup() {
const state = reactive({
user: null,
isAuthenticated: false,
permissions: [],
});
const actions = {
login: async (credentials: any) => {
// Login logic
state.user = await authenticate(credentials);
state.isAuthenticated = true;
state.permissions = await getUserPermissions(state.user.id);
},
logout: () => {
state.user = null;
state.isAuthenticated = false;
state.permissions = [];
},
};
// Provide readonly state and actions
provide("auth", {
state: readonly(state),
actions,
});
return {};
},
};
// Consumer component
import { inject, computed } from "@vue/composition-api";
export default {
setup() {
const auth = inject("auth");
const canEditPosts = computed(() => {
return auth?.state.permissions.includes("edit:posts") ?? false;
});
const handleLogin = async () => {
await auth?.actions.login({ username: "user", password: "pass" });
};
return {
auth,
canEditPosts,
handleLogin,
};
},
};Service Injection Pattern:
import { provide, inject, InjectionKey } from "@vue/composition-api";
// Service interface
interface ApiService {
get<T>(url: string): Promise<T>;
post<T>(url: string, data: any): Promise<T>;
put<T>(url: string, data: any): Promise<T>;
delete(url: string): Promise<void>;
}
// Service implementation
class HttpApiService implements ApiService {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
async get<T>(url: string): Promise<T> {
const response = await fetch(`${this.baseUrl}${url}`);
return response.json();
}
async post<T>(url: string, data: any): Promise<T> {
const response = await fetch(`${this.baseUrl}${url}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
return response.json();
}
async put<T>(url: string, data: any): Promise<T> {
const response = await fetch(`${this.baseUrl}${url}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
return response.json();
}
async delete(url: string): Promise<void> {
await fetch(`${this.baseUrl}${url}`, { method: "DELETE" });
}
}
// Service key
const ApiServiceKey: InjectionKey<ApiService> = Symbol("apiService");
// Root component provides service
export default {
setup() {
const apiService = new HttpApiService("/api");
provide(ApiServiceKey, apiService);
return {};
},
};
// Component uses service
export default {
setup() {
const api = inject(ApiServiceKey);
const loadData = async () => {
if (api) {
const data = await api.get("/users");
console.log("Users:", data);
}
};
return {
loadData,
};
},
};Configuration Injection:
import { provide, inject, InjectionKey } from "@vue/composition-api";
interface AppConfig {
apiUrl: string;
version: string;
features: {
darkMode: boolean;
notifications: boolean;
analytics: boolean;
};
}
const ConfigKey: InjectionKey<AppConfig> = Symbol("config");
// App root provides configuration
export default {
setup() {
const config: AppConfig = {
apiUrl: process.env.VUE_APP_API_URL || "/api",
version: process.env.VUE_APP_VERSION || "1.0.0",
features: {
darkMode: true,
notifications: true,
analytics: process.env.NODE_ENV === "production",
},
};
provide(ConfigKey, config);
return {};
},
};
// Component uses configuration
export default {
setup() {
const config = inject(ConfigKey, {
apiUrl: "/api",
version: "unknown",
features: { darkMode: false, notifications: false, analytics: false },
});
return {
config,
};
},
};Providers can override values at different levels of the component tree, allowing for contextual customization.
import { provide, inject } from "@vue/composition-api";
// Root level provider
export const RootProvider = {
setup() {
provide("theme", "light");
provide("lang", "en");
return {};
},
};
// Section level provider (overrides theme)
export const DarkSection = {
setup() {
provide("theme", "dark"); // Overrides root theme
// lang is still "en" from root
return {};
},
};
// Component uses nearest provider
export const ThemedComponent = {
setup() {
const theme = inject("theme", "light"); // Gets "dark" from DarkSection
const lang = inject("lang", "en"); // Gets "en" from root
return {
theme,
lang,
};
},
};Creating reusable composables that encapsulate injection logic.
import { inject, InjectionKey, computed } from "@vue/composition-api";
interface User {
id: string;
name: string;
email: string;
role: string;
}
const UserKey: InjectionKey<User | null> = Symbol("user");
// Composable for user injection
export function useUser() {
const user = inject(UserKey, null);
const isLoggedIn = computed(() => user !== null);
const isAdmin = computed(() => user?.role === "admin" ?? false);
const canEdit = computed(() => isAdmin.value || user?.role === "editor");
return {
user,
isLoggedIn,
isAdmin,
canEdit,
};
}
// Usage in component
export default {
setup() {
const { user, isLoggedIn, isAdmin, canEdit } = useUser();
return {
user,
isLoggedIn,
isAdmin,
canEdit,
};
},
};interface InjectionKey<T> extends Symbol {}
type InjectionConstraint = string | number | boolean | object | symbol;
interface ProvideOptions {
[key: string | symbol]: any;
}
interface InjectOptions {
from?: string | symbol;
default?: any;
}
type InjectKey = string | symbol;Install with Tessl CLI
npx tessl i tessl/npm-vue--composition-api