Pinia学习
- pinia
- 安装
- 写法
- 注意
- getter 传递参数
- 访问其他 store 的 getter
- Action
- action 异步方法
- 访问其他 store 的 action
pinia
Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。
Pinia 的核心概念包括 state(状态)、getter(获取器)和 action(行为),这些可以类比为组件中的 data、computed 和 methods。Store(如 Pinia)是一个保存状态和业务逻辑的实体,它不与组件树绑定,承载着全局状态。
安装
npm install pinia//引用
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'const pinia = createPinia()
const app = createApp(App)app.use(pinia)
app.mount('#app')
写法
1、选项式 API: 选项式 API 是一种更接近 Vuex 的写法,其中 defineStore 函数接受一个对象,这个对象包含了 state, actions, getters 等属性。例如:
import { defineStore } from 'pinia';const useUserStore = defineStore('user', {state: () => ({name: 'Eduardo',age: 24,}),actions: {setName(name) {this.name = name;},},getters: {fullName: (state) => `${state.name} Doe`,},
});
//在组件中使用
import { useUserStore } from '@/stores/user';export default {setup() {const userStore = useUserStore();// 访问状态console.log(userStore.name);// 访问 gettersconsole.log(userStore.fullName);// 调用 actionsuserStore.changeName('John');},
};
2、组合式 API: 组合式 API 是 Vue 3 引入的一种新写法,它允许开发者更灵活地组合和重用逻辑。在这种方式中,defineStore 仍然被用来定义 store,但是 storeToRefs 用于将 store 中的响应式状态解构为单独的响应式引用。例如:
import { defineStore } from 'pinia';const useUserStore = defineStore('user', () => {const name = ref('Eduardo');const age = ref(24);function setName(newName) {name.value = newName;}// 使用 computed 来定义 gettersconst fullName = computed(() => `${name.value} Doe`);return { name, age, setName };
});
// 在组件中使用
import { useUserStore } from '@/stores/user';const userStore = useUserStore();//方法一, 使用 storeToRefs 保持响应性
//const { name, age, setName ,fullName } = storeToRefs(userStore);//方法二
// 使用 store 的状态和函数console.log(userStore.name);console.log(userStore.fullName);console.log(userStore.age);userStore.setName('John');
注意
store 是一个用 reactive 包装的对象,这意味着不需要在 getters 后面写 .value。就像 setup 中的 props 一样,我们不能对它进行解构:
在组件中,你就不需要使用 .value 来访问 name 或 fullName。只有在 store 的内部,当你直接操作 ref 对象时,才需要使用 .value
getter 传递参数
在 Pinia 中,getter 本质上是 Store 状态的派生状态,它们是响应式的计算属性。默认情况下,getter 不接受参数,但你可以通过返回一个函数来绕过这个限制,这样就可以向这个函数传递参数。
import { defineStore } from 'pinia';export const useUserStore = defineStore('user', {state: () => ({users: [{ id: 1, name: 'Eduardo' },{ id: 2, name: 'John' },// ... 其他用户],}),getters: {getUserById: (state) => {// 返回一个函数,该函数接受参数return (userId) => {// 在函数内部使用参数并返回结果return state.users.find((user) => user.id === userId);};// return (userId) => state.users.find((user) => user.id === userId)},},
});
在组件中使用时,你可以这样调用这个 getter:
import { useUserStore } from '@/stores/user';export default {setup() {const userStore = useUserStore();// 获取特定用户const user = userStore.getUserById(1);console.log(user); // { id: 1, name: 'Eduardo' }// 如果需要响应式,可以使用 computedconst userId = ref(1);const specificUser = computed(() => userStore.getUserById(userId.value));console.log(specificUser.value); // { id: 1, name: 'Eduardo' }// 更改用户 IDuserId.value = 2;console.log(specificUser.value); // { id: 2, name: 'John' }},
};
访问其他 store 的 getter
import { useOtherStore } from './other-store'export const useStore = defineStore('main', {state: () => ({// ...}),getters: {otherGetter(state) {const otherStore = useOtherStore()return state.localData + otherStore.data},},
})
Action
Action 相当于组件中的 method。它们可以通过 defineStore() 中的 actions 属性来定义,并且它们也是定义业务逻辑的完美选择,action 可以是异步的,你可以在它们里面 await 调用任何 API。
export const useCounterStore = defineStore('main', {state: () => ({count: 0,}),actions: {increment() {this.count++},randomizeCounter() {this.count = Math.round(100 * Math.random())},},
})
action 异步方法
import { mande } from 'mande'const api = mande('/api/users')export const useUsers = defineStore('users', {state: () => ({userData: null,// ...}),actions: {async registerUser(login, password) {try {this.userData = await api.post({ login, password })showTooltip(`Welcome back ${this.userData.name}!`)} catch (error) {showTooltip(error)// 让表单组件显示错误return error}},},
})
访问其他 store 的 action
import { useAuthStore } from './auth-store'export const useSettingsStore = defineStore('settings', {state: () => ({preferences: null,// ...}),actions: {async fetchUserPreferences() {const auth = useAuthStore()if (auth.isAuthenticated) {this.preferences = await fetchPreferences()} else {throw new Error('User must be authenticated')}},},
})