# State

大多数时候,stateStore的中心部分。人们通常从定义应用程序的state开始。在Pinia 中,state被定义为一个返回初始state的函数。这保证了Pinia在服务器端和客户端都能使用。

import { defineStore } from 'pinia'

const useStore = defineStore('storeId', {
  // arrow function recommended for full type inference
  state: () => {
    return {
      // all these properties will have their type inferred automatically
      counter: 0,
      name: 'Eduardo',
      isAdmin: true,
    }
  },
})

TIP

如果您使用Vue 2,您在state中创建的数据应遵循与Vue实例中data相同的规则,即 state对象必须是普通的,并且在向其添加新属性时需要调用Vue.set()。另请参阅:Vue#data (opens new window)

# 访问State

默认情况下,你可以通过Store实例直接读写state:

const store = useStore()

store.counter++

# 重置State

您可以通过调用store上的$reset()方法将state重置为初始值:

const store = useStore()

store.$reset()

# 使用Options API

对于以下示例,您可以假设创建了以下store:

// Example File Path:
// ./src/stores/counterStore.js

import { defineStore } from 'pinia'

const useCounterStore = defineStore('counterStore', {
  state: () => ({
    counter: 0
  })
})

# 使用setup()

虽然Composition API并不适合所有人,但是setup()钩子可以让Pinia更容易在Options API中使用。不需要额外的辅助函数!

import { useCounterStore } from '../stores/counterStore'

export default {
  setup() {
    const counterStore = useCounterStore()

    return { counterStore }
  },
  computed: {
    tripleCounter() {
      return counterStore.counter * 3
    },
  },
}

# 不使用setup()

如果您不使用Composition API,而您使用的是computed, methods,…,则你可以使用mapState()辅助函数将状态属性映射为只读计算属性:

import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'

export default {
  computed: {
    // gives access to this.counter inside the component
    // same as reading from store.counter
    ...mapState(useCounterStore, ['counter']),
    // same as above but registers it as this.myOwnName
    ...mapState(useCounterStore, {
      myOwnName: 'counter',
      // you can also write a function that gets access to the store
      double: store => store.counter * 2,
      // it can have access to `this` but it won't be typed correctly...
      magicValue(store) {
        return store.someGetter + this.counter + this.double
      },
    }),
  },
}

# 可修改的 State

如果您希望能够写入这些状态属性(例如,如果您有一个表单),您可以使用mapWritableState()代替。请注意,您不能像mapState()那样传递函数:

import { mapWritableState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'

export default {
  computed: {
    // gives access to this.counter inside the component and allows setting it
    // this.counter++
    // same as reading from store.counter
    ...mapWritableState(useCounterStore, ['counter']),
    // same as above but registers it as this.myOwnName
    ...mapWritableState(useCounterStore, {
      myOwnName: 'counter',
    }),
  },
}

TIP 您不需要mapWritableState()来处理像数组这样的集合,除非你用cartItems = []来替换整个数组,mapState()仍然允许你在你的集合上调用方法。

# 改变 State

除了直接使用store.counter++ 改变store之外,你也可以调用$patch方法。它允许您使用部分state对象同时应用到多个改变:

store.$patch({
  counter: store.counter + 1,
  name: 'Abalam',
})

然而,使用这种语法应用某些改变确实很难或代价高昂:任何集合修改(例如,从数组中添加、删除、修改元素)都需要您创建一个新集合。正因为如此,$patch方法也接受一个函数来对这种难以应用于patch对象的改变进行分组:

cartStore.$patch((state) => {
  state.items.push({ name: 'shoes', quantity: 1 })
  state.hasChanged = true
})

这里的主要区别是$patch()允许您在devtools中将多个改变分组到一个条目中。注意,对**state$patch()**的直接更改将呈现在devtools中,并且需要花费些时间(在Vue 3中还没出现)。

# 替换 State

您可以通过将store$state属性设置一个新对象来替换整个store的状态:

store.$state = { counter: 666, name: 'Paimon' }

您还可以通过更改 pinia实例的state来替换应用程序的整个状态。这在SSR激活 (opens new window)中使用。

pinia.state.value = {}

# 订阅 State

您可以通过store$subscribe()方法查看状态及其变化,这与Vuexsubscribe 方法 (opens new window)类似。与常规的watch()相比,使用$subscribe()的优势在于,订阅只会在patches之后触发一次(例如,当使用上面的函数版本时)。

cartStore.$subscribe((mutation, state) => {
  // import { MutationType } from 'pinia'
  mutation.type // 'direct' | 'patch object' | 'patch function'
  // same as cartStore.$id
  mutation.storeId // 'cart'
  // only available with mutation.type === 'patch object'
  mutation.payload // patch object passed to cartStore.$patch()

  // persist the whole state to the local storage whenever it changes
  localStorage.setItem('cart', JSON.stringify(state))
})

默认情况下,状态订阅被绑定到添加它们的组件上(如果store在组件的setup()中)。这意味着,当组件被卸载时,它们将被自动删除。如果你想在组件卸载后保留它们,传递{ detached: true } 作为第二个参数来从当前组件中分离状态订阅:

export default {
  setup() {
    const someStore = useSomeStore()

    // this subscription will be kept after the component is unmounted
    someStore.$subscribe(callback, { detached: true })

    // ...
  },
}

TIP 您可以查看`Pinia```实例上的整个状态:

watch(
  pinia.state,
  (state) => {
    // persist the whole state to the local storage whenever it changes
    localStorage.setItem('piniaState', JSON.stringify(state))
  },
  { deep: true }
)