Pinia 最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法。最终,我们意识到 Pinia 已经实现了我们在 Vuex 5 中想要的大部分内容,并决定实现它 取而代之的是新的建议。
可以理解为pinia就是下一代的vuex5,但是vuex团队为了尊重pinia作者对于vuex的开发贡献,就直接使用pinia命名了。
pinia中文文档
用你最喜欢的包管理器安装 pinia:
yarn add pinia
# 或者使用 npm
npm install pinia
使用createPinia将pinia引入项目中。
main.ts:
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).use(createPinia()).mount('#app')
src目录下创建store文件夹,用于存放store对应的js/ts文件,未来方便管理,我们可以在一个js/ts文件中只定义一个store,例如我们定义一个user.ts文件,用于存储用户相关的信息和操作:
pinia使用defineStore创建store,包含了id、state、getters和actions:
// @ts-check
import { defineStore } from 'pinia'
/**
* Simulate a login
*/
function apiLogin(a: string, p: string) {
if (a === 'ed' && p === 'ed') return Promise.resolve({ isAdmin: true })
if (p === 'ed') return Promise.resolve({ isAdmin: false })
return Promise.reject(new Error('invalid credentials'))
}
export const useUserStore = defineStore({
id: 'user',
state: () => ({
name: 'Eduardo',
isAdmin: true,
}),
getters:{
userName: (state) => `Get userName from getter ${state.name}`
},
actions: {
/**
* 退出logout
*/
logout() {
this.$patch({
name: '',
isAdmin: false,
})
/**
* 登录 login
*/
async login(user: string, password: string) {
const userData = await apiLogin(user, password)
this.$patch({
name: user,
...userData,
})
},
},
})
相比较于vuex,pinia去除了mutation,同步和异步操作都通过actions,并且没有了module的概念,defineStore会创建一个新的store。
在组件中引入定义好的store并调用:
<script setup lang="ts">
import { useUserStore } from "./store/user"
const userStore = useUserStore()
//访问state
console.log(userStore.name)
//访问getter
console.log(userStore.userName)
script>
然后就可以通过user来访问store中的state,并且还可以调用getter和action。
Getter 完全等同于 Store 状态的计算值
。 它们可以用 defineStore() 中的 getters 属性定义。 他们接收“状态”作为第一个参数以鼓励箭头函数的使用,可以直接在 store 实例上访问 getter。
我们也可以在定义常规函数时通过 this 访问到整个 store 的实例。
Actions 相当于组件中的 methods。 它们可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑,也可以直接在store实例上调用action。
在actions中也可以在定义常规函数时通过 this 访问到整个 store 的实例。
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
actions: {
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
},
})
虽然可以通过pinia实例直接修改,但是出于代码结构来说,全局的状态管理还是不要直接在各个组件处随意修改状态,应放于 action 中统一方法修改(piain没有mutation)并不推荐!
store.count ++;
使用$patch改变数据 $patch 可以同时修改多个值。
store.$patch((state) => {
state.name= 'newName'
state.age ++
})
推荐。
actions:{
async login(user: string, password: string) {
//模拟异步登录
const userData = await apiLogin(user, password)
//更新state中数据
this.$patch({
name: user,
...userData,
})
}
}
为了直接获取store中的属性,我们可能会利用解构来直接获取:
import { useUserStore } from "./store/user"
const { name }= useUserStore()
但是,值得注意的是,如果直接解构store实例来获取state中的值,那么获取的值就失去了响应式,正确的做法是使用storeToRefs:
import { storeToRefs } from 'pinia'
import { useUserStore } from "./store/user"
const { name }= storeToRefs(useUserStore())