Sharing Global State with Vue 3 Provide/Inject
Owner: SnippetBot
Created: 2026-11-05 00:00:42
Size: 2.33 KB
Expires: Never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// main.js (or main.ts)
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
// App.vue (Parent Component that Provides)
<template>
<div :class="{ 'dark-theme': theme.theme.value === 'dark' }" class="app-container">
<h1>Parent Component (Theme: {{ theme.theme.value }})</h1>
<ChildComponent />
<button @click="theme.toggleTheme">Toggle Theme from App.vue</button>
</div>
</template>
<script>
import { provide, ref, readonly } from 'vue';
import ChildComponent from './components/ChildComponent.vue';
export default {
components: { ChildComponent },
setup() {
const appName = ref('My Awesome App');
const theme = ref('light');
const toggleTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
};
// Provide a readonly reactive value for appName
provide('appName', readonly(appName));
// Provide a reactive value and a method to modify it for theme
provide('theme', {
theme: readonly(theme), // Expose theme as readonly
toggleTheme // Expose the method to change theme
});
return {
theme // Expose theme to App.vue's template for its own class binding
};
},
};
</script>
<style>
.app-container {
padding: 20px;
border: 2px solid #3498db;
border-radius: 10px;
margin-bottom: 20px;
}
.dark-theme {
background-color: #333;
color: white;
}
</button> {
margin-top: 10px;
padding: 8px 15px;
border-radius: 4px;
cursor: pointer;
}
</style>
// components/ChildComponent.vue (Child Component that Injects)
<template>
<div :class="{ 'dark-theme': theme.theme.value === 'dark' }" class="child-container">
<h2>Child Component</h2>
<p>App Name from Parent: {{ appName }}</p>
<p>Current Theme: {{ theme.theme.value }}</p>
<button @click="theme.toggleTheme">Toggle Theme from Child</button>
</div>
</template>
<script>
import { inject } from 'vue';
export default {
setup() {
// Inject values provided by a parent
const appName = inject('appName');
const theme = inject('theme'); // Injects { theme: Ref<string>, toggleTheme: Function }
return {
appName,
theme,
};
},
};
</script>
<style scoped>
.child-container {
padding: 15px;
border: 1px dashed #2ecc71;
border-radius: 8px;
margin: 10px 0;
}
.dark-theme {
background-color: #555;
color: #eee;
}
</style>