前言
Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。 如果您熟悉 Composition API ,您可能会认为您已经可以通过一个简单的 export const state = reactive({}) . 这对于单页应用程序来说是正确的,但如果它是服务器端呈现的,会使您的应用程序暴露于安全漏洞。 但即使在小型单页应用程序中,您也可以从使用 Pinia 中获得很多好处:
-
dev-tools 支持 1、跟踪动作、突变的时间线 2、Store 出现在使用它们的组件中 3、time travel 和 更容易的调试 -
热模块更换 1、在不重新加载页面的情况下修改您的 Store 2、在开发时保持任何现有状态 -
插件:使用插件扩展 Pinia 功能 -
为 JS 用户提供适当的 TypeScript 支持或 autocompletion -
服务器端渲染支持
一、基本示例
这就是使用 pinia 在 API 方面的样子。 您首先创建一个 Store :
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 }
},
actions: {
increment() {
this.count++
},
},
})
然后你在一个组件中 使用 它:
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const counter = useCounterStore()
counter.count++
counter.$patch({ count: counter.count + 1 })
counter.increment()
},
}
你甚至可以使用一个函数(类似于一个组件setup() )来为更高级的用例定义一个Store :
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
如果你还不熟悉 setup() 和 Composition API ,别担心,Pinia 也支持一组类似的 map helpers like Vuex 。 您以相同的方式定义存储,但随后使用 mapStores() 、mapState() 或 mapActions() :
const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
}
}
})
const useUserStore = defineStore('user', {
})
export default {
computed: {
...mapStores(useCounterStore, useUserStore)
...mapState(useCounterStore, ['count', 'double']),
},
methods: {
...mapActions(useCounterStore, ['increment']),
},
}
二、一个更现实的例子
这是一个更完整的 API 示例,您将与 Pinia 一起使用即使在 JavaScript 中也具有类型。 对于某些人来说,这可能足以在不进一步阅读的情况下开始使用,但我们仍然建议您查看文档的其余部分,甚至跳过此示例,并在阅读完所有_核心概念_后返回。
import { defineStore } from 'pinia'
export const todos = defineStore('todos', {
state: () => ({
todos: [],
filter: 'all',
nextId: 0,
}),
getters: {
finishedTodos(state) {
return state.todos.filter((todo) => todo.isFinished)
},
unfinishedTodos(state) {
return state.todos.filter((todo) => !todo.isFinished)
},
filteredTodos(state) {
if (this.filter === 'finished') {
return this.finishedTodos
} else if (this.filter === 'unfinished') {
return this.unfinishedTodos
}
return this.todos
},
},
actions: {
addTodo(text) {
this.todos.push({ text, id: this.nextId++, isFinished: false })
},
},
})
三、与 Vuex 的比较
Pinia 最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法。最终,我们意识到 Pinia 已经实现了我们在 Vuex 5 中想要的大部分内容,并决定实现它 取而代之的是新的建议。
与 Vuex 相比,Pinia 提供了一个更简单的 API ,具有更少的规范,提供了 Composition-API 风格的 API ,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。
RFC# 虽然 Vuex 通过 RFC 从社区收集尽可能多的反馈,但 Pinia 没有。 我根据我开发应用程序、阅读其他人的代码、为使用 Pinia 的客户工作以及在 Discord 上回答问题的经验来测试想法。 这使我能够提供一种适用于各种情况和应用程序大小的有效解决方案。 我经常发布并在保持其核心 API 不变的同时使库不断发展。
1、与 Vuex 3.x/4.x 的比较
| Vuex 3.x 是 Vuex 的 Vue 2 而 Vuex 4.x 是 Vue 3
Pinia API 与 Vuex ≤4 有很大不同,即:
mutations 不再存在。他们经常被认为是 非常 冗长。他们最初带来了 devtools 集成,但这不再是问题。- 无需创建自定义复杂包装器来支持
TypeScript ,所有内容都是类型化的,并且 API 的设计方式尽可能利用 TS 类型推断。 - 不再需要注入、导入函数、调用函数、享受自动完成功能!
- 无需动态添加
Store ,默认情况下它们都是动态的,您甚至都不会注意到。请注意,您仍然可以随时手动使用 Store 进行注册,但因为它是自动的,您无需担心。 - 不再有 modules 的嵌套结构。您仍然可以通过在另一个
Store 中导入和 使用 来隐式嵌套 Store ,但 Pinia 通过设计提供平面结构,同时仍然支持 Store 之间的交叉组合方式。 您甚至可以拥有 Store 的循环依赖关系。 - 没有 命名空间模块。鉴于
Store 的扁平架构,“命名空间” Store 是其定义方式所固有的,您可以说所有 Store 都是命名空间的。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了Pinia 的使用。
|