目录
一、简介
二、入门
1、安装
2、何为 Store ?
3、何时使用 Store ?
三、基本使用
1、Store
2、State?
定义 state
获取 state
重置 state
更换 state
修改 state
订阅(监听)state?
3、Getters
创建 getters
使用其他 getters
访问其他 store 中的 getters
4、Actions
创建 actions
异步 actions
访问其他 store 中的 actions
订阅 actions
四、与 Vuex 的比较
1、优缺点
Vuex 的优点
Vuex 的缺点
Pinia 的优点
Pinia 的缺点
2、使用场景
五、总结
一、简介
Pinia 是 Vue 的存储库,它允许你跨组件/页面共享状态。如果你熟悉 Composition API,你可能已经使用过简单的export const state = reactive({}), ?这对于单页应用程序来说是正确的,但如果它是服务器端呈现的,则会将你的应用程序暴露给安全漏洞。
即使在小型单页应用程序中,你也可以从使用 Pinia 中获得很多好处:
- 开发工具支持
- 跟踪动作、突变的时间表
- store只出现在使用它们的组件中
- 时间旅行和更容易的调试
- 热模块更新
- 在不重新加载页面的情况下修改你的store
- 在开发时保持任何现有状态
- 插件:使用插件扩展 Pinia 功能
- 为 JS 用户提供适当的 TypeScript 支持或自动完成功能
- 服务器端渲染(SSR)支持
?Pinia 有以下特点:
-
完整的 TypeScript 的支持; -
足够轻量,压缩后的体积约2kb; -
去除 mutations,只有 state,getters,actions; -
actions 支持同步和异步; -
没有模块嵌套,只有 store 的概念,store 之间可以自由使用,更好的代码分割; -
无需手动添加 store,store 一旦创建便会自动添加;?
二、入门
1、安装
yarn add pinia
// or with npm
npm install pinia
注意:
如果你的应用使用 Vue2,你还需要安装composition api:@vue/composition-api; 如果你使用 Nuxt,则应遵循这些说明;如果你使用的是 Vue CLI,你可以试试这个非官方的插件。
2、何为 Store ?
一个 Store(如 Pinia)是一个实体,它持有未绑定到你的组件树的状态和业务逻辑。换句话说,它托管全局状态。它有点像一个始终存在并且每个人都可以读取和写入的组件。它包含三个概念,state、getters?和?actions,并且可以假设这些概念等同与 data、computed 和 methods 在组件中。
3、何时使用 Store ?
Store 应该包含可以在整个应用程序中访问的数据。这包括在许多地方使用的数据,例如在导航栏中显示的用户信息,以及需要通过页面保存的数据,如非常复杂的多步骤表单。
另一方面,你应该避免在 Store 中包含可能托管在组件中的本地数据,例如页面本地元素的可见性。并非所有应用程序都需要访问全局状态,但如果你需要,Pania 将使你能更轻松地完成。
三、基本使用
1、Store
在 main.js 中创建并使用
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
const app = createApp(App);
const pinia = createPinia();
app.use(pinia).mount('#app');
2、State?
定义 state
在 src/pinia?下面创建一个 count.js
import { defineStore } from 'pinia'
export const useStore = defineStore({
id: 'count', // id必填,且需要唯一
state: () => {
return {
count: 0
}
}
})
// 另外一种方式
export const useStore = defineStore('count', { // 将id作为第一个参数
state: () => {
return {
count: 0
}
}
})
获取 state
<template>
<div>
<p>{{ countStore.count }}</p>
</div>
</template>
<script>
import { useStore } from "../pinia/count.js";
export default {
setup() {
let countStore = useStore();
return {
countStore
};
}
}
</script>
也可以结合 computed 获取
let count = computed(() => countStore.count)
state 也可以使用解构,但使用解构会使其失去响应式,这时候可以用 pinia 的?storeToRefs
import { storeToRefs } from 'pinia';
let { count } = storeToRefs(countStore);
重置 state
可以通过调用 store 上的方法将 state?重置为其初始值:$reset()
let countStore = useStore();
countStore.$reset();
更换 state
可以通过将 store 中的$state 属性设置为新对象来替换 store 的整个 state
let countStore = useStore();
countStore.$state = { count: 0 };
修改 state
可以如下直接修改 state
let countStore = useStore();
countStore.count++
但一般不建议这么做,而是通过 actions?去修改 state,actions 里可以直接通过 this 访问
// count.js
export const useStore = defineStore({
id: 'count',
state: () => {
return {
count: 0
}
},
actions: { // 建议通过action修改state,更符合业务逻辑
increment() {
this.count++
}
}
})
<script>
import { useStore } from "../pinia/count.js";
export default {
setup() {
let countStore = useStore();
countStore.increment(); // 通过actions修改state,更符合业务逻辑
return {
countStore
};
}
}
</script>
订阅(监听)state?
可以通过$subscribe() 观察 state 及其变化,类似于 Vuex 的subscribe 方法
let countStore = useStore();
countStore.$subscribe((mutation, state) => {
console.log(mutation);
console.log("监听count变化触发的回调,count的值为:", state.count);
count = state.count;
});
// 可以在监听到state变化后执行某些操作
当 state 变化时,控制台打印
3、Getters
创建 getters
export const useStore = defineStore({
id: 'count',
state: () => {
return {
count: 0
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
}
})
使用其他 getters
大多数时候,getters 只会依赖状态,但是有时候可能需要使用其他 getters
export const useStore = defineStore({
id: 'count',
state: () => {
return {
count: 0
}
},
getters: {
doubleCount(state) {
return state.count * 2;
},
doublePlusOne() {
return this.doubleCount + 1;
}
}
})
可以直接在 countStore 实例上访问 getters
<template>
<div>
<p>{{ countStore.doubleCount }}</p>
<p>{{ countStore.doublePlusOne }}</p>
</div>
</template>
访问其他 store 中的 getters
import { useOtherStore } from './other-store'
export const useStore = defineStore({
id: 'count',
state: () => ({
// ...
}),
getters: {
otherGetter(state) {
let otherStore = useOtherStore();
return state.count + otherStore.data;
},
},
})
4、Actions
创建 actions
export const useStore = defineStore({
id: 'count',
state: () => {
return {
count: 0
}
},
actions: {
increment() {
this.count++;
},
randomCount() {
this.count = Math.round(100 * Math.random());
}
}
})
像 getters 一样,actions 通过完全输入(和自动完成)支持访问整个 store 实例。与它们不同的是,它可以是异步的。
异步 actions
actions 可以像写一个简单的函数一样支持 async/await 的语法,让你愉快地应付异步处理的场景
export const useStore = defineStore({
id: 'login',
actions: {
async login(account, pwd) {
let { data } = await api.login(account, pwd);
return data;
}
}
})
访问其他 store 中的 actions
import { useAuthStore } from './auth-store'
export const useSettingsStore = defineStore({
id: 'settings',
state: () => ({
// ...
}),
actions: {
async fetchUserPreferences(preferences) {
let authStore = useAuthStore();
if (authStore.isAuthenticated) {
this.preferences = await fetchPreferences();
} else {
throw new Error('User must be authenticated');
}
}
}
})
订阅 actions
可以使用store.$onAction() 观察 actions 及其结果。传递给它的回调在操作本身之前执行。after 处理承诺并允许你更改操作的返回值。onError 允许你阻止错误传播。这些对于在运行时跟踪错误很有用,类似于Vue 文档中的这个技巧。
这是一个在运行操作之前和它们解决/拒绝之后记录的示例
// 订阅(监听)actions
store.$onAction(
({
name, // name of the action
store, // store instance, same as `someStore`
args, // array of parameters passed to the action
after, // hook after the action returns or resolves
onError, // hook if the action throws or rejects
}) => {
console.log("name:",name);
console.log("store:",store);
console.log("before store.count:",store.count);
console.log("args",args);
// this will trigger if the action succeeds and after it has fully run.
// it waits for any returned promised
after(() => {
console.log("after store.count:",store.count);
});
// this will trigger if the action throws or returns a promise that rejects
onError((error) => {
console.log(error);
});
}
);
当触发 actions 时,控制台打印
默认情况下,操作订阅绑定到添加它们的组件(如果 store 位于组件的 内部setup() )。意思是,当组件被卸载时,它们将被自动删除。如果要在卸载组件后保留它们,请将true 作为第二个参数传递来把操作订阅与当前组件分离
export default {
setup() {
let someStore = useSomeStore();
// this subscription will be kept after the component is unmounted
someStore.$onAction(callback, true)
// ...
},
}
四、与 Vuex 的比较
1、优缺点
Vuex 的优点
-
支持调试功能,如时间旅行和编辑 -
适用于大型、高复杂度的Vue.js项目
Vuex 的缺点
Pinia 的优点
-
完整的 TypeScript 支持:与在 Vuex 中添加 TypeScript 相比,添加 TypeScript 更容易 -
极其轻巧(体积约 1KB) -
store 的 action 被调度为常规的函数调用,而不是使用?dispatch ?方法或?MapAction ?辅助函数,这在 Vuex 中很常见 -
支持多个Store -
支持 Vue devtools、SSR 和 webpack 代码拆分
Pinia 的缺点
2、使用场景
由于Pinea是轻量级的,体积很小,它比较适合中小型应用。它也适用于低复杂度的Vue.js项目,因为调试功一些能,如时间旅行和编辑仍然不被支持。
将 Vuex 用于中小型 Vue.js 项目是过度的,因为它重量级的,对性能降低有很大影响。因此,Vuex 适用于大规模、高复杂度的 Vue.js 项目。
据Vue.js 核心团队成员并积极参与 Vuex 设计的 Pinia 的创建者(Eduardo San Martin Morote)所说,Pania 和 Vuex 的相似之处多于不同之处:
Pinia 试图尽可能地接近 Vuex 的理念。它的设计是为了测试 Vuex 的下一次迭代的建议,它是成功的,因为我们目前有一个开放的 RFC,用于 Vuex5,其API与 Pinea 使用的非常相似。我对这个项目的个人意图是重新设计使用全局 store 的体验,同时保持 Vue 的平易近人的理念。我保持 Pinea 的API与 Vuex 一样接近,因为它不断向前发展,使人们很容易迁移到Vuex,甚至在未来融合两个项目(在Vuex下)。?
五、总结
以上就是关于 Pinia 的一些基本介绍,Pinia 的内容远远不止这些,对于我们使用者而言,首先掌握最基本用法,然后再去深入更多的用法,如在 Pinia 中使用插件来扩展功能等。
更多内容请前往官网了解
Piniahttps://pinia.vuejs.org/欢迎大家一键三连,一起学前端,一起进步~~~
|