Core concepts of Pinia (store/state/getters/actions)
Pinia is a lightweight state management library for Vue.js, offering core concepts such as stores, state, getters, and actions to simplify global state management. Below is a detailed breakdown of these concepts, their specific usage, and best practices in real-world scenarios.
Store
The store is the core unit of Pinia, with each store corresponding to an independent state container. It is created using the defineStore
function and supports both the Option API and Setup API styles.
// Options API style
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
double: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
// Composition API style
export const useUserStore = defineStore('user', () => {
const name = ref('Alice')
const age = ref(25)
const isAdult = computed(() => age.value >= 18)
function growUp() {
age.value++
}
return { name, age, isAdult, growUp }
})
Stores are reactive. To maintain reactivity when using them in components, ensure the reference remains unchanged:
// Correct usage
const store = useStore()
// Incorrect usage (loses reactivity)
const { count } = useStore()
State
State is the reactive data source of a store and supports all JavaScript types. There are four primary ways to modify state:
- Direct modification (Composition API only)
const store = useStore()
store.count++
- Batch updates using
$patch
store.$patch({
count: store.count + 1,
name: 'Bob'
})
// Or using a function
store.$patch((state) => {
state.items.push({ id: 1 })
state.hasChanged = true
})
- Replace the entire state
store.$state = { count: 10, name: 'Charlie' }
- Modify via actions (recommended)
// Defined in the store
actions: {
reset() {
this.$reset() // Reset to initial state
}
}
Getters
Getters are equivalent to computed properties in a store and have caching capabilities. They can access the entire store instance via this
:
getters: {
// Basic getter
doubleCount: (state) => state.count * 2,
// Using other getters
quadrupleCount() {
return this.doubleCount * 2
},
// Parameterized getter
getUserById: (state) => {
return (id) => state.users.find(user => user.id === id)
}
}
Using getters in components:
const store = useStore()
// Direct access
console.log(store.doubleCount)
// Calling with parameters
console.log(store.getUserById(101))
Actions
Actions are methods in a store and support both synchronous and asynchronous operations. Unlike Vuex, Pinia's actions are plain functions:
actions: {
async fetchUser(userId) {
try {
this.isLoading = true
const response = await api.getUser(userId)
this.user = response.data
} catch (error) {
this.error = error
} finally {
this.isLoading = false
}
},
// Combining multiple actions
async fetchUserAndPosts(userId) {
await this.fetchUser(userId)
await this.fetchPosts(userId)
}
}
Calling actions does not require dispatch
; they can be called directly:
const store = useStore()
store.fetchUser(123)
Advanced Usage
Subscribing to State Changes
// Listening to the entire store
const unsubscribe = store.$subscribe((mutation, state) => {
console.log('Change type:', mutation.type)
console.log('Modified data:', mutation.payload)
})
// Listening to specific state
watch(
() => store.count,
(newVal) => {
console.log('Count changed:', newVal)
}
)
Plugin Extensions
Example of creating a Pinia plugin:
function localStoragePlugin(context) {
const key = `pinia-${context.store.$id}`
// Restore state from local storage
const savedState = localStorage.getItem(key)
if (savedState) {
context.store.$patch(JSON.parse(savedState))
}
// Subscribe to changes
context.store.$subscribe((_, state) => {
localStorage.setItem(key, JSON.stringify(state))
})
}
const pinia = createPinia()
pinia.use(localStoragePlugin)
Server-Side Rendering (SSR)
Special handling is required when using with Nuxt.js:
// nuxt.config.js
export default {
modules: ['@pinia/nuxt'],
pinia: {
autoImports: ['defineStore']
}
}
// Usage example
export const useStore = defineStore('main', {
state: () => ({ counter: 0 }),
hydrate(storeState, initialState) {
storeState.counter = initialState.counter || 42
}
})
Performance Optimization
- Avoid expensive computations in getters:
// Not recommended
getters: {
heavyComputation() {
return bigData.value.filter(/* complex computation */)
}
}
// Recommended: use computed for caching
const heavyComputation = computed(() => {
return bigData.value.filter(/* complex computation */)
})
- Use
$patch
for batch updates:
// Inefficient
store.name = 'Alice'
store.age = 25
store.role = 'admin'
// Efficient
store.$patch({
name: 'Alice',
age: 25,
role: 'admin'
})
- Split stores by feature in large applications:
stores/
├── auth.store.js
├── cart.store.js
├── product.store.js
└── user.store.js
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:Pinia与Vuex对比
下一篇:陈川的代码茶馆🍵