阿里云主机折上折
  • 微信号
Current Site:Index > Core concepts of Pinia (store/state/getters/actions)

Core concepts of Pinia (store/state/getters/actions)

Author:Chuan Chen 阅读数:2855人阅读 分类: Vue.js

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:

  1. Direct modification (Composition API only)
const store = useStore()
store.count++
  1. 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
})
  1. Replace the entire state
store.$state = { count: 10, name: 'Charlie' }
  1. 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

  1. 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 */)
})
  1. Use $patch for batch updates:
// Inefficient
store.name = 'Alice'
store.age = 25
store.role = 'admin'

// Efficient
store.$patch({
  name: 'Alice',
  age: 25,
  role: 'admin'
})
  1. Split stores by feature in large applications:
stores/
├── auth.store.js
├── cart.store.js
├── product.store.js
└── user.store.js

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.