Simple state management can be performed by creating a store pattern that involves sharing a data store between components. The store can manage the state of our application as well as the methods that are responsible in changing the state.
Step one is to create a place where we can put all of our data.
We'll create a basic Javascript object:
const store = {};
We can store our data in a single place, but we still have some issues:
- We need to share this between all of our components
- We want this to be reactive
We'll put this object into a file called store.js
.
To share it with other components, we'll first have to export it from this file:
// store.js
export default {
movies: [],
};
Then for any component that needs to use the data store we can import it:
import store from './store.js';
export default {
name: 'CoolestComponent',
};
But using it is pretty tricky with Vue.
Right now it's not reactive, so it's impossible for us to know when something has been updated.
Currently this data store is only good for providing data on initialization.
In this example, if store.movies
is updated after the component is created, nothing will happen:
import store from './store.js';
export default {
name: 'MovieList',
data() {
return {
movies: store.movies,
};
},
};
Making it reactive
Luckily Vue makes this part super easy for us with the Vue.observable
function.
It takes in any object, and returns a copy of it that's reactive.
We'll use this on our data store to make it reactive:
// store.js
import Vue from 'vue';
export default Vue.observable({
movies: [],
});
That's the final step!
Now let's look at how we'll actually use this in a component.
This is where we left off with our example:
import store from './store.js';
export default {
name: 'MovieList',
data() {
return {
movies: store.movies,
};
},
};
but this component needs nothing added to it. It's already pulling the list of movies from the store, so it's doing everything it needs to.
Because the store is now reactive, whenever that value is updated it will update automatically and render the new list of movies.
What we need next is a way to load these movies in!
We'll create another component that does that:
// load-movies.vue
import store from './store.js';
import MoviesAPI from './moviesAPI.js';
export default {
name: 'LoadMovies',
methods: {
async loadMovies() {
// Add movies to our fancy data store
store.movies = await MoviesAPI.getMovies();
},
},
};
When the loadMovies
method is called on this other component, it will fetch all of the movies and add them to our data store.
Example 2:
For example, we can have a simple store like the following:
export const store = {
state: {
numbers: [1, 2, 3]
},
addNumber(newNumber) {
this.state.numbers.push(newNumber);
}
};
The store contains a numbers
array within its state, and an addNumber
method that accepts a payload and directly updates the state.numbers
value.
We can have one component that’s responsible in displaying the numbers
array from the store that we’ll call NumberDisplay
:
<template>
<div>
<h2>{{ storeState.numbers }}</h2>
</div>
</template>
<script>
import { store } from "../store.js";
export default {
name: "NumberDisplay",
data() {
return {
storeState: store.state
};
}
};
</script>
We can now have another component, called NumberSubmit
, that will allow the user to add a new number to our data array:
<template>
<div>
<input v-model="numberInput" type="number" />
<button @click="addNumber(numberInput)">
Add new number
</button>
</div>
</template>
<script>
import { store } from "../store.js";
export default {
name: "NumberSubmit",
data() {
return {
numberInput: 0
};
},
methods: {
addNumber(numberInput) {
store.addNumber(Number(numberInput));
}
}
};
</script>
The NumberSubmit
component has an addNumber()
method that calls the store.addNumber()
mutation and passes the expected payload.
The store method receives the payload and directly mutates the store.numbers
array. Thanks to Vue’s reactivity, whenever the numbers
array in store state gets changed, the relevant DOM that depends on this value (<template>
of NumberDisplay
) automatically updates.
When we say components interact with one another here, we’re using the term ‘interact’ loosely. The components aren’t going to do anything to each other but instead invoke changes to one another through the store.