经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
Pinia入门学习之实现简单的用户状态管理
来源:jb51  时间:2022/12/2 10:59:09  对本文有异议

Store是什么?

全局状态,用于在所有组件中,同步数据。

Store的应用场景?

在整个应用程序中访问的数据(且不需要被持久化),例如导航栏中显示的用户信息,以及需要通过页面保留的数据,例如一个非常复杂的多步骤表格。

pinia是什么?

简单一句介绍,vuex的升级版,抛弃了烦人的Mutation。

其他优点

  • action支持同步和异步;
  • 良好的TypeScript支持;
  • 支持用插件扩展功能;
  • 扁平架构,没有嵌套;
  • 服务端渲染支持。

应用示例

下面我们以一个管理平台的员工账号信息为例,展示Pinia的使用方式。

本文作者认为setup是更好的组织代码的方式,所以都用setup编写下面的示例。

安装和挂载部分,直接看文档

定义Store

  1. import { defineStore } from 'pinia'
  2.  
  3. // 第一个参数是应用程序中 store 的唯一 id
  4. export const useUserStore = defineStore('user', {
  5. // other options...
  6. })

使用Store

  1. import { useUserStore } from '@/stores/user'
  2.  
  3. export default {
  4. setup() {
  5. const userStore = useUserStore()
  6.  
  7. return {
  8. // 您可以返回整个 store 实例以在模板中使用它
  9. userStore,
  10. }
  11. },
  12. }

(如果习惯用选项式API,还是可以配合map helpers,声明各种map来访问store。)

获取store的响应式数据

直接解构会破坏响应式,需要用storeToRefs()提取属性并保持响应式。

  1. import { storeToRefs } from 'pinia'
  2.  
  3. export default defineComponent({
  4. setup() {
  5. const userStore = useUserStore()
  6. // ? 这不起作用,因为它会破坏响应式
  7. // 这和从 props 解构是一样的
  8. const { userName } = userStore
  9. // 这样可以保持响应式
  10. const { userId } = storeToRefs(userStore)
  11.  
  12. userName // "lucio"
  13. userId // "001"
  14.  
  15. return {
  16. // 一直会是 "lucio"
  17. userName,
  18. // 这将是响应式的
  19. userId,
  20. // 这将是响应式的
  21. realUserName: computed(() => userStore.userName),
  22. }
  23. },
  24. })

State

返回初始状态的函数。

我们补全一下上面的定义Store部分的代码。

初始化

  1. import { defineStore } from 'pinia'
  2.  
  3. // 第一个参数是应用程序中 store 的唯一 id
  4. export const useUserStore = defineStore('user', {
  5. state: () => {
  6. return {
  7. // 所有这些属性都将自动推断其类型
  8. userName: 'lucio',
  9. userId: '001',
  10. }
  11. },
  12. })

读取和写入state

  • 通过store示例,可读写。
  1. const userStore = useUserStore()
  2. userStore.userId = '002'
  3. userStore.$reset()
  4. return { userStore }
  • 通过$patch修改多个数据,参数可以是对象或者函数。
  1. // 一次修改多个数据
  2. userStore.$patch({
  3. userId: '002',
  4. userName: 'lucy',
  5. })
  6. // 适合对数组进行修改
  7. userStore.$patch((state) => {
  8. state.roles.push({ name: 'admin', priority: 1 })
  9. })
  • 替换整个state
  1. userStore.$state = { userId: '002', userName: 'lucy'}
  2. // 或者通过pinia实例替换整个应用程序的状态
  3. pinia.state.value = {}

订阅state变化

可以通过 store 的 $subscribe() 方法查看状态及其变化,其只在patch之后触发一次。

默认情况下,组件卸载后,订阅会被删除。如果想保留,设置配置项detached为true。

  1. userStore.$subscribe((mutation, state) => {
  2. // import { MutationType } from 'pinia'
  3. mutation.type // 'direct' | 'patch object' | 'patch function'
  4. // 与 userStore.$id 相同
  5. mutation.storeId // 'user'
  6. // 仅适用于 mutation.type === 'patch object'
  7. mutation.payload // 补丁对象传递给 to userStore.$patch()
  8.  
  9. // 每当它发生变化时,将整个状态持久化到本地存储
  10. localStorage.setItem('user', JSON.stringify(state))
  11. },
  12. { detached: true }, // detached为true,卸载组件后保留订阅
  13. )

Getters

返回状态的计算值

定义getter

  1. import { defineStore } from 'pinia'
  2.  
  3. // 第一个参数是应用程序中 store 的唯一 id
  4. export const useUserStore = defineStore('user', {
  5. state: () => {
  6. return {
  7. // 所有这些属性都将自动推断其类型
  8. userName: 'lucio',
  9. userId: '001',
  10. }
  11. },
  12. getters: {
  13. // 自动推断返回类型为字符串
  14. userText: (state) => `User: ${state.userName}`,
  15. // 也可以使用其他getter, 用this访问store实例,必须要定义返回类型
  16. userTextPlus: (): string => `The name of ${this.userText}`,
  17. }
  18. })

访问getter

直接用store的实例访问。

  1. userStore.userText

(getters也可以传递参数,不是很常用的场景,这里就不示例了。)

(在A store中,也可以使用B store的getter)

Actions

相当于组件中的methods,适合用于定义组件的业务逻辑。

定义action

下面我们继续补全上面的示例,在userStore中通过网络请求获取用户数据。

  1. import { defineStore } from 'pinia'
  2.  
  3. export const useUserStore = defineStore('user', {
  4. state: () => {
  5. return {
  6. userName: 'lucio',
  7. userId: '001',
  8. userData: null,
  9. }
  10. },
  11. getters: {
  12. // ...
  13. },
  14. actions: {
  15. async loginAndGetUserInfo(password) {
  16. try {
  17. this.userData = await api.login({password});
  18. showToast('Login success');
  19. } catch(error) {
  20. showToast(error);
  21. return error;
  22. }
  23. }
  24. }
  25. })

订阅action

可以使用 store.$onAction() 订阅 action 及其结果。

下面对userStore添加一个订阅,记录上面的登陆操作,所用的时间

  1. const unsubscribe = userStore.$onAction(
  2. ({
  3. name, // action 的名字
  4. store, // store 实例
  5. args, // 调用这个 action 的参数
  6. after, // 在这个 action 执行完毕之后,执行这个函数
  7. onError, // 在这个 action 抛出异常的时候,执行这个函数
  8. }) => {
  9. // 记录开始的时间变量
  10. const startTime = Date.now()
  11. // 这将在 `store` 上的操作执行之前触发
  12. console.log(`Start "${name}" with params [${args.join(', ')}].`)
  13.  
  14. // 如果 action 成功并且完全运行后,after 将触发。
  15. // 它将等待任何返回的 promise
  16. after((result) => {
  17. console.log(
  18. `Finished "${name}" after ${
  19. Date.now() - startTime
  20. }ms.\nResult: ${result}.`
  21. )
  22. })
  23.  
  24. // 如果 action 抛出或返回 Promise.reject ,onError 将触发
  25. onError((error) => {
  26. console.warn(
  27. `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
  28. )
  29. })
  30. }
  31. )
  32.  
  33. // 手动移除订阅
  34. unsubscribe()

和订阅state一样,组件卸载时,订阅将被删除,可以添加设置第二个参数detach为true,在卸载组件后仍然保留订阅。

  1. export default {
  2. setup() {
  3. const someStore = useSomeStore()
  4.  
  5. // 此订阅将在组件卸载后保留
  6. someStore.$onAction(callback, true)
  7.  
  8. // ...
  9. },
  10. }

总结

到此这篇关于Pinia入门学习之实现简单的用户状态管理的文章就介绍到这了,更多相关Pinia用户状态管理内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号