setup写法
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})
//使用
<script setup>
import { useCounterStore } from '@/stores/counter'
// 可以在组件中的任意位置访问 `store` 变量 ✨
const store = useCounterStore()
</script>
store
是一个用 reactive
包装的对象,这意味着不需要在 getters 后面写 .value
(自动解包)。就像 setup
中的 props
一样,我们不能对它进行解构:
<script setup>
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
// ❌ 这将不起作用,因为它破坏了响应性
// 这就和直接解构 `props` 一样
const { name, doubleCount } = store
name // 将始终是 "Eduardo"
doubleCount // 将始终是 0
setTimeout(() => {
store.increment()
}, 1000)
</script>
从 Store 解构
解构需要使用storeToRefs
,对应action直接解构就可以使用
<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// `name` 和 `doubleCount` 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } = storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } = store
</script>
你可以在 pinia
实例上使用 watch()
函数侦听整个 state。
watch(
pinia.state,
(state) => {
// 每当状态发生变化时,将整个 state 持久化到本地存储。
localStorage.setItem('piniaState', JSON.stringify(state))
},
{ deep: true }
)
在组件外使用 store
为确保 pinia 实例被激活,最简单的方法就是将 useStore()
的调用放在 pinia 安装后才会执行的函数中。
import { createRouter } from 'vue-router'
const router = createRouter({
// ...
})
// ❌ 由于引入顺序的问题,这将失败
const store = useStore()
router.beforeEach((to, from, next) => {
// 我们想要在这里使用 store
if (store.isLoggedIn) next()
else next('/login')
})
router.beforeEach((to) => {
// ✅ 这样做是可行的,因为路由器是在其被安装之后开始导航的,
// 而此时 Pinia 也已经被安装。
const store = useStore()
if (to.meta.requiresAuth && !store.isLoggedIn) return '/login'
})