I have a Vue.js 3 app. This app includes multiple single file components. I'm trying to figure out how to implement the simplest global state management. The docs make sense to me. However, the limited docs show a reactive
object returned from the data
function of multiple components. This example assumes the reactive
object and components are all in the same file. The challenge I'm running into is using a shared store across multiple files. Currently I have:
- app.vue
- component-a.vue
- component-b.vue
- store.js
These files looks like this:
app.vue
<template>
<div>
<div>How much money do you have?</div>
<input type="number" v-model="currentAmount" />
<br />
<div>How much money do you want?</div>
<input type="number" v-model="desiredAmount" />
</div>
</template>
<script>
import ComponentA from './component-a.vue';
import ComponentB from './component-b.vue';
export default {
components: {
ComponentA,
ComponentB
},
data() {
return {
currentAmount: 0,
desiredAmount: 0
}
},
}
</script>
component-a.vue
<template>
<div>
<div>You have {{ remainingAmount }} to reach your goal.</div>
</div>
</template>
<script>
export default {
data() {
return {
remainingAmount: 0
}
},
}
</script>
component-b.vue
<template>
<div>
<div>You are {{ progress }}% of the way there!</div>
<button @click="increaseGoal">increase goal by $10</button>
</div>
</template>
<script>
export default {
data() {
return {
progress: 0
}
},
methods: {
increaseGoal() {
// need to increase targetAmount by $10
store.targetAmount = 10;
}
}
}
</script>
store.js
import { reactive} from 'vue';
const store = reactive({
startingAmount: 0,
targetAmount: 0
});
The UI renders. However, clearly the data is not getting propagated across the components. I can clearly see that there's not a link between store and the three .vue files. There's nothing that ties the store with the UI. I don't know how to get the store.js
associated with the three .vue files properly though.
How do you link a shared store with multiple single file components? Please note: I do not want to use Vuex.
CodePudding user response:
To get hold of the store on a global level you can make vue use()
it so that you will be able to call this.$store
from any component within the VueApp
main.js
import { createApp } from 'vue';
import store from './store/index'; // OR the path to your
import router from './router/index';
import App from './App.vue';
createApp(App).use(router).use(store).mount('#app');
I created a store-folder because I use the store within multiple modules.
In the store folder is the index.js
which hold the basics store and all modules.
store/index.js
import { createStore } from 'vuex';
const store = createStore({
modules: {},
state() {
return {};
},
mutations: {},
actions: {},
getters: {},
});
export default store;
By doing that you can call the store from any component.
component.vue
export default {
name: 'users-list',
created() {
console.log(this.$store);
},
}
The variables in your store's state should not be altered directly.
The store has 3 types of procedures.
Actions - Do elaborated Stuff
The Actions are used to do the heavy work of a given change in data. This is where you would cross-feed the function from different store modules, make axios calls and similar. Therefore Actions is the only procedure group that can access the store it-self. the first argument is basically the whole store.
Actions are triggered by calling dispatch('NameOfModule/NameOfAction', ValuetoPass)
.
Mutations - Beloved Setter Functions
The Mutations are used to mutate a state, and ONLY Mutations should mutate the state in order to keep reactivity and workflows clean.
The Mutations therefore only get passed their own local state as first parameter. Mutations will be triggered by commit('NameOfMutation', ValueToPass)
Getters - Pretty self-explanatory, isn't it?
The getters are used to, well yeah, get States.
CodePudding user response:
As you said, you don't need to use Vuex to create global state. Thanks to composition-api we can use composables.
First, create directory /composables and add javascript file (it's good practice to create file beginning with use word) useState.js:
import { reactive, toRefs } from "vue";
const state = reactive({
isMenuOpened: false
});
const toggleMenuState = () => {
state.isMenuOpened = !state.isMenuOpened;
};
export default {
...toRefs(state),
toggleMenuState
};
toRefs converts all of the properties, to a plain object with properties that are refs
Now you can use composable in vue components:
<script>
import useState from "./composables/useState";
export default {
setup() {
const { isMenuOpened, toggleMenuState } = useState;
return {
isMenuOpened,
toggleMenuState,
};
},
};
</script>
Demo: https://codesandbox.io/s/happy-chandrasekhar-o05uv?file=/src/App.vue
About composition api and composables: https://v3.vuejs.org/guide/composition-api-introduction.html