'Watch Vue 3 global variable for changes
I set a provider in my main.ts
file:
app.provide('currentPage','test1')
And then inject it in a component Home.vue
:
inject: ['currentPage'],
I then can update it and show it in that component without a problem using {{ currentPage }}
.
But I want another component DeepNestedComponent.vue
to be able to edit it, and Home.vue
to be aware of the change.
When I inject the same provider in DeepNestedComponent.vue
, I can edit and display in the component, but Home.vue
is not aware of the change and {{ currentPage }}
still display 'test1'.
How can I do that?
Solution 1:[1]
This pattern is designed only to pass some property from grandparent component to grandchild one, your case needs a shareable state based on Vuex or a composable function, let's build a solution based on the second approach :
define the composable function :
usePagination.ts
import { ref } from "vue";
const currentPage=ref('test')
export default function usePagination(){
function setCurrentPage(val:string){
currentPage.value=val;
}
return {currentPage, setCurrentPage}
}
DeepNestedComponent.vue
import usePagination from './usePagination'
...
setup(){
const { setCurrentPage} =usePagination();
// then use setCurrentPage to update the page
}
Home.vue :
import usePagination from './usePagination'
...
setup(){
const { currentPage} =usePagination();
// now you could receive the changes made in the other component.
return {
currentPage // expose it to the template
}
}
Solution 2:[2]
provide/inject
is meant strictly for passing something down the hierarchy (kind of similar to dependency injection). It does not mutate/decorate the given target. This means if you provide a string, it will be consumed (injected) as a string, and a string by itself is not reactive.
If you want it to be reactive, you need to provide a reactive object or reference:
<script>
import {defineComponent, ref, provide} from 'vue';
import Parent from "./Parent.vue";
export default defineComponent({
setup (){
const msg = ref("Hello World");
provide("message", msg);
return {msg};
},
components: {
Parent
}
});
</script>
Solution 3:[3]
vue3 Reactive/Watchable Global Variables
In main.js
import { ref } from 'vue';
app.config.globalProperties.$currentPage = ref("Page 1");
Watch the variable in some file (Home.vue)
<template>
<div>{{ currentPage }}</div>
</template>
<script>
export default {
name: "App",
data(){
return {
currentPage: "test1"
}
},
mounted() {
this.updateCurrentPage()
},
watch: {
'$currentPage.value':{
handler: function () {
this.updateCurrentPage()
}, deep: true }
},
methods: {
updateCurrentPage(){
this.currentPage = this.$currentPage.value
}
}
}
</script>
Change the variable in another (DeepNestedComponent.vue)
<template>
<div>
<button @click="changePage()">changePage</button>
</div>
</template>
<script>
export default {
name: 'DeepNestedComponent',
data(){
return {
pageCount: 0
}
},
methods:{
changePage(){
this.pageCount = this.pageCount + 1
const pageValue = `Page ${this.pageCount}`
this.$currentPage = pageValue
}
}
}
</script>
Found this solution from "Vue3 reactive components on globalProperties" when I was looking to set a global variable for my websites color scheme
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Xinchao |
Solution 3 |