Vuex State Management: When Do You Actually Need It?
Everyone talks about Vuex, but do you really need it? Here’s my take after using it in production for 6 months.
What is Vuex?
Vuex is a state management library for Vue. Think Redux for Vue, but simpler.
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
})
When You DON’T Need Vuex
Small Apps (< 10 Components)
For small apps, props and events are enough:
<!-- Parent.vue -->
<template>
<Child :user="user" @update="handleUpdate" />
</template>
<script>
export default {
data() {
return { user: {} }
},
methods: {
handleUpdate(newUser) {
this.user = newUser
}
}
}
</script>
Simple Data Flow
If data flows in one direction (parent → child), you don’t need Vuex.
No Shared State
If components don’t share state, Vuex is overkill.
When You DO Need Vuex
Multiple Components Need Same Data
// Without Vuex - prop drilling hell
<GrandParent>
<Parent :user="user">
<Child :user="user">
<GrandChild :user="user" />
</Child>
</Parent>
</GrandParent>
// With Vuex - access anywhere
computed: {
user() {
return this.$store.state.user
}
}
Complex State Logic
When state updates involve multiple steps:
actions: {
async login({ commit }, credentials) {
commit('SET_LOADING', true)
try {
const user = await api.login(credentials)
commit('SET_USER', user)
commit('SET_AUTHENTICATED', true)
} catch (error) {
commit('SET_ERROR', error)
} finally {
commit('SET_LOADING', false)
}
}
}
Need Time-Travel Debugging
Vuex integrates with Vue DevTools for time-travel debugging. Super useful for tracking down bugs.
Our Vuex Structure
store/
├── index.js
├── modules/
│ ├── auth.js
│ ├── users.js
│ └── products.js
└── plugins/
└── logger.js
Each module handles its own domain:
// store/modules/auth.js
export default {
namespaced: true,
state: {
user: null,
token: null
},
mutations: {
SET_USER(state, user) {
state.user = user
},
SET_TOKEN(state, token) {
state.token = token
}
},
actions: {
async login({ commit }, credentials) {
const { user, token } = await api.login(credentials)
commit('SET_USER', user)
commit('SET_TOKEN', token)
}
},
getters: {
isAuthenticated: state => !!state.token
}
}
Best Practices
1. Use Modules
Don’t put everything in one store. Split by domain.
2. Use Getters for Computed State
getters: {
activeUsers: state => {
return state.users.filter(u => u.active)
}
}
3. Actions for Async, Mutations for Sync
// Good
actions: {
async fetchUsers({ commit }) {
const users = await api.getUsers()
commit('SET_USERS', users)
}
}
// Bad - async in mutation
mutations: {
async SET_USERS(state) {
state.users = await api.getUsers() // Don't do this!
}
}
4. Use Constants for Mutation Types
// mutation-types.js
export const SET_USER = 'SET_USER'
export const SET_LOADING = 'SET_LOADING'
// store.js
import * as types from './mutation-types'
mutations: {
[types.SET_USER](state, user) {
state.user = user
}
}
Common Mistakes
1. Putting Everything in Vuex
Not everything needs to be in the store. Component-local state is fine for UI state (modals, tabs, etc.).
2. Mutating State Directly
// Bad
this.$store.state.user.name = 'John'
// Good
this.$store.commit('SET_USER_NAME', 'John')
3. Not Using Namespaces
Without namespaces, all mutations/actions are global. Use namespaced: true.
Performance
Vuex is fast. We have a store with 10,000+ items, and it’s still snappy. Vue’s reactivity system handles it well.
Testing
Vuex makes testing easier:
import { mutations } from './store'
describe('mutations', () => {
it('SET_USER', () => {
const state = { user: null }
mutations.SET_USER(state, { name: 'John' })
expect(state.user.name).toBe('John')
})
})
The Verdict
Use Vuex if:
- App has > 10 components
- Multiple components share state
- State logic is complex
- You need time-travel debugging
Don’t use Vuex if:
- App is small
- Data flow is simple
- No shared state
For us, Vuex was the right choice. Our app has 50+ components with lots of shared state. Vuex keeps it manageable.
Start without Vuex. Add it when you feel the pain of prop drilling and event bubbling.
Questions? Ask away!