Persisting user authentication with Vuex in Vue
This post assumes that you at least have some working knowledge of Vue and Redux.
What is Vuex?
Vuex is a state management pattern for Vue applications.
The basic idea behind Vuex, inspired by Flux, Redux, and The Elm Architecture.
The benefits of Vuex:
- Unlike other Redux implementations, you don’t need to use immutability to improve your app performance.
- Built in side effects management with actions. There is no reason to use third-party middleware like
redux-thunk
. - Built in support for getters.
- Built in support for modules and dynamic module registration.
We are going to create a simple app that will simulate authentication.
For the simplicity, we are not going to use the vue-cli
, we will write all the code in a simple javascript file that works on a plunker.
Preparations —
First, we need to include the libraries in our HTML file:
We also need the router-view
component that will render our router components.
Create the Vue app —
The code is straightforward. We have two routes:
- The Home page that will render the
Home
component. - The Login page that will render the
Login
component.
The store —
Let’s see the different pieces that make up Vuex store.
State —
The state object is a single object contains all your application level state and serves as the “single source of truth.”
In our app, we need to know if the user is logged in by checking if the user has a token
in the browser local storage.
Mutations —
In Vuex mutations are the equivalents of reducers in Redux. The key difference is that you don’t have to use immutability to improve your performance.
Commits —
In Vuex commits are the equivalents of actions in Redux. The only way to change state in a Vuex store is by committing a mutation. Mutation handler functions must be synchronous.
Actions —
In Vuex the way to handle side effects ( like asynchronous operations ) is by dispatching actions. Actions commit mutations.
In our app, we have two actions:
The login action flow:
1. Commit LOGIN
mutation. ( useful for showing a spinner ).
2. Returning a promise because when the operation complete we want to register a function that will redirect the user to the homepage from our component.
2. Simulate asynchronous operation with the setTimeout
function. ( like HTTP request )
3. Save the JWT to local storage.
4. Commit LOGIN_SUCCESS
mutation that will change the isLoggedIn
state to true.
5. Resolve the promise.
The logout action flow:
1. Remove the JWT from local storage.
2. Commit LOGOUT
mutation that will change the isLoggedIn
state to false.
Getters —
In Vuex getters are the equivalents of selectors
in Redux.
The final step is to pass the store
to our Vue app:
const app = new Vue({
router,
store
}).$mount(‘#app’)
By providing the store
option to the root instance, the store will be injected into all child components of the root and will be available on them as this.$store
.
The Components —
Home component —
Main nav component —
The main-nav
component is responsible for displaying our main navigation. First, we are setting a computed property as a getter
from our store, every time there is a change in our isLoggedIn
state, Vue will re-render the component.
Next, we are setting a logout
method that will dispatch the logout
action, remove the token from local storage, and commit LOGOUT
mutation that will set the isLoggedIn
state to false.
Quick tip: You can use Vuex helpers to make your life easier:
methods: {
...Vuex.mapActions([“logout”])}
}
getters: {
...Vuex.mapGetters([“isLoggedIn”])
}
Login component —
The Login component is a simple form with email and password. When the user submits the form, we are dispatching the login
action, and when the promise is resolved, we are redirecting the user to the homepage.
Improvements:
- Add a spinner with the help of the
pending
state. - Add Error handling.
- Add Navigation Guards.
- Extract this to a self-contained
auth
module.
You can find the final code here.
Follow me on Medium or Twitter to read more about Vue, Angular and JS!