Perhaps you've heard of Vuex and you're wondering what it is. What does it do? Why does it exist? How do I use it? If these questions are on your mind you've come to the right place! In this series of articles, we'll take a look at Vuex, the official Vue.js store solution, as well as some alternatives that can serve the same purpose but with different approaches. By the end of the series you should have a good grasp on Vuex and other Vue.js store solutions and be well prepared to implement the store solution best suited for your project and coding style.
You've probably noticed I keep using the term store but what does that mean? In Vue, as well as other front end frameworks like React, a store is a centralized location to keep up with data that is available across all the application components.
A logged in user is a perfect example of data that belongs in a store. You'll probably need to access it in a navigation bar component to show the user at a glance that they're logged in. You'll probably need a user profile page component. You'll also probably need another component for editing that user's details. Perhaps you'll need access to that user's data in some component that makes posts in your application whether it's a forum, a blog, or a social platform, so that you can save who created the post.
If we didn't have a centralized store, we would have to pass that logged in user data down through props. If the component tree is multiple levels deep, we'd need to catch and pass the data for each level. This can quickly become unmaintainable, plus we'd also have to do the same for events if we wanted to communicate with the parents.
By having a centralized store, we reduce the complexity of needing to pass/catch props and events up and down multiple levels.
Rules for Mutating Store Data
Not only does the store provide a centralized place for your multi-component data to live, it's also responsible for defining how that data is manipulated and changed (this is what we call mutations). This means making changes to the data in the store can be accomplished through semantically named functions or "actions". Your components should not and need not know the underlying data structure to manipulate it, instead they just the need to know the action name and the parameters it takes (if any).
Take the logged in user example again. Let's say due to the database structure of your application, every time a user creates a new post, you must update a user property
numberOfPosts. Instead of directly updating
user.numberOfPosts in your component, you call an action
incrementUserPostsCount. Now this action can be used in multiple places with a one-line call to the action and you don't have to know anything about the user object itself. Then in the action, should incrementing the user's post count ever take on any extra steps you can do it in one spot and the action call doesn't have to change at all in the components.
Another advantage of the store defining all the rules on how to manipulate it's data, is that you can look in one place (usually in a single file) and see all the manipulation possibilities at once. You don't have to scour you're entire codebase to see how different pieces of data are subject to change, you just look at the defined actions.
Finally, delegating mutations of your store data to the store actions and not allowing anything outside of those actions to change it means that you can keep pieces of data that shouldn't be arbitrarily changed safe.
Again, think of the logged in user. Certainly your application should never be able to change that users id. Sure the components might need to read it sometimes, that's no problem with a store but the components shouldn't be able to change it. So, simply don't expose an action from the store to mutate the id and now it's safe and you can be assured it will never change.
So that's a store in a nutshell. It's a centralized location for data needed across multiple disparate components with centrally defined rules on how those pieces of data can be changed.
It's worth noting, this pattern is not isolated to Vue. It's a tried and true practice throughout many front-end frameworks. For instance, the common solution for React is Redux and for Angular, NgRx. While implementations differ, understanding the basics of how a store works will prepare you to be productive no matter your framework of choice.
When is a Store Needed?
Now that you know what it is, it's important to know when you should implement a store in your application. Many simple applications can probably go their entire lifetime without needing a store solution or can stick to a simpler no library based store but as applications grow the need for a store will often become apparent.
If you've started your application with thorough planning and have wire-framed out different pages and interactions you should be able to see pieces of data that pop-up across different pages or on different parts of the page. That's a good sign you'll probably need a store.
If you're already into the development process without a store and find yourself emitting data up through multiple components via events or passing data down through multiple components via props, here's your sign: You probably need a store.
Finally, if you know your application has the potential to grow in size to become a "large" application, I think it's best to start out the codebase with a store and use good discretion on when to utilize it. It's easier to work with the elevated complexities of a store from the beginning than to refactor a store-less project to include a store or push a store-less project far too long without it for the sake of not having to refactor it.
So far, we've talked about what a store is, why it's useful, and when is a good time to put one into place. Pretty much everything we've talked about so far could apply to any front-end framework: Vue, React, Angular, whatever. But how do we actually implement a store in Vue.js? In the rest of this series, we'll dive into some of the specific options available to us, starting with Vuex.