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);
// 访问 getters
console.log(userStore.fullName);
// 调用 actions
userStore.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 来定义 getters
const 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' }
// 如果需要响应式,可以使用 computed
const userId = ref(1);
const specificUser = computed(() => userStore.getUserById(userId.value));
console.log(specificUser.value); // { id: 1, name: 'Eduardo' }
// 更改用户 ID
userId.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')
}
},
},
})