共享数据的方式

三种方案

  • vuex方案
  • global state 方案
  • provide&inject 方案

vuex方案

安装vuex@4.x
两个重要变动:

  • 去掉了构造函数Vuex,而使用createStore创建仓库
  • 为了配合composition api,新增useStore函数获得仓库对象
    1. import * as userServ from "../api/user";
    2. export default {
    3. namespaced: true,
    4. state: {
    5. user: null,
    6. loading: false,
    7. },
    8. mutations: {
    9. setUser(state, payload) {
    10. state.user = payload;
    11. },
    12. setLoading(state, payload) {
    13. state.loading = payload;
    14. },
    15. },
    16. actions: {
    17. async login({ commit }, { loginId, loginPwd }) {
    18. commit("setLoading", true);
    19. const user = await userServ.login(loginId, loginPwd);
    20. commit("setUser", user);
    21. commit("setLoading", false);
    22. return user;
    23. },
    24. async loginOut({ commit }) {
    25. commit("setLoading", true);
    26. await userServ.loginOut();
    27. commit("setUser", null);
    28. commit("setLoading", false);
    29. },
    30. async whoAmI({ commit }) {
    31. commit("setLoading", true);
    32. const user = await userServ.whoAmI();
    33. commit("setUser", user);
    34. commit("setLoading", false);
    35. },
    36. },
    37. };

    示例代码

    demo-vuex.rar

    global state

    由于vue3的响应式系统本身可以脱离组件而存在,因此可以充分利用这一点,轻松制造多个全局响应式数据
    共享数据 - 图1 ```javascript // store/useLoginUser 提供当前登录用户的共享数据 // 以下代码仅供参考 import { reactive, readonly } from “vue”; import * as userServ from “../api/user”; // 导入api模块 // 创建默认的全局单例响应式数据,仅供该模块内部使用 const state = reactive({ user: null, loading: false }); // 对外暴露的数据是只读的,不能直接修改 // 也可以进一步使用toRefs进行封装,从而避免解构或展开后响应式丢失 export const loginUserStore = readonly(state);

// 登录 export async function login(loginId, loginPwd) { state.loading = true; const user = await userServ.login(loginId, loginPwd); state.loginUser = user; state.loading = false; } // 退出 export async function loginOut() { state.loading = true; await userServ.loginOut(); state.loading = false; state.loginUser = null; } // 恢复登录状态 export async function whoAmI() { state.loading = true; const user = await userServ.whoAmI(); state.loading = false; state.loginUser = user; }

  1. <a name="GOhkh"></a>
  2. ### 示例代码
  3. [demo-compositionApi.rar](https://www.yuque.com/attachments/yuque/0/2021/rar/1376603/1623907597087-4042999a-8902-4d14-9fc7-412e7845d918.rar?_lake_card=%7B%22uid%22%3A%221623907588103-0%22%2C%22src%22%3A%22https%3A%2F%2Fwww.yuque.com%2Fattachments%2Fyuque%2F0%2F2021%2Frar%2F1376603%2F1623907597087-4042999a-8902-4d14-9fc7-412e7845d918.rar%22%2C%22name%22%3A%22demo-compositionApi.rar%22%2C%22size%22%3A11588792%2C%22type%22%3A%22%22%2C%22ext%22%3A%22rar%22%2C%22progress%22%3A%7B%22percent%22%3A99%7D%2C%22status%22%3A%22done%22%2C%22percent%22%3A0%2C%22id%22%3A%22eR7eo%22%2C%22card%22%3A%22file%22%7D)
  4. <a name="0fI9W"></a>
  5. # Provide&Inject
  6. 在`vue2`中,提供了`provide`和`inject`配置,可以让开发者在高层组件中注入数据,然后在后代组件中使用<br />![](https://cdn.nlark.com/yuque/0/2021/png/1376603/1623916748050-c6e12e23-5be6-41cd-aee3-f5e98ec64068.png#align=left&display=inline&height=772&margin=%5Bobject%20Object%5D&originHeight=772&originWidth=1464&size=0&status=done&style=stroke&width=1464)<br />除了兼容`vue2`的配置式注入,`vue3`在`composition api`中添加了`provide`和`inject`方法,可以在`setup`函数中注入和使用数据<br />![](https://cdn.nlark.com/yuque/0/2021/png/1376603/1623916773721-cbb3c3d8-6b81-439f-ab2e-b588ed06c9e9.png#align=left&display=inline&height=770&margin=%5Bobject%20Object%5D&originHeight=770&originWidth=1448&size=0&status=done&style=stroke&width=1448)<br />考虑到有些数据需要在整个vue应用中使用,`vue3`还在应用实例中加入了`provide`方法,用于提供整个应用的共享数据
  7. ```vue
  8. creaetApp(App)
  9. .provide("foo", ref(1))
  10. .provide("bar", ref(2))
  11. .mount("#app");

共享数据 - 图2
因此,我们可以利用这一点,在整个vue应用中提供共享数据

  1. // store/useLoginUser 提供当前登录用户的共享数据
  2. // 以下代码仅供参考
  3. import { readonly, reactive, inject } from "vue";
  4. const key = Symbol(); // Provide的key
  5. // 在传入的vue应用实例中提供数据
  6. export function provideStore(app) {
  7. // 创建默认的响应式数据
  8. const state = reactive({ user: null, loading: false });
  9. // 登录
  10. async function login(loginId, loginPwd) {
  11. state.loading = true;
  12. const user = await userServ.login(loginId, loginPwd);
  13. state.loginUser = user;
  14. state.loading = false;
  15. }
  16. // 退出
  17. async function loginOut() {
  18. state.loading = true;
  19. await userServ.loginOut();
  20. state.loading = false;
  21. state.loginUser = null;
  22. }
  23. // 恢复登录状态
  24. async function whoAmI() {
  25. state.loading = true;
  26. const user = await userServ.whoAmI();
  27. state.loading = false;
  28. state.loginUser = user;
  29. }
  30. // 提供全局数据
  31. app.provide(key, {
  32. state: readonly(state), // 对外只读
  33. login,
  34. loginOut,
  35. whoAmI,
  36. });
  37. }
  38. export function useStore(defaultValue = null) {
  39. return inject(key, defaultValue);
  40. }
  41. // store/index
  42. // 应用所有store
  43. import { provideStore as provideLoginUserStore } from "./useLoginUser";
  44. // 继续导入其他共享数据模块...
  45. // import { provideStore as provideNewsStore } from "./useNews"
  46. // 提供统一的数据注入接口
  47. export default function provideStore(app) {
  48. provideLoginUserStore(app);
  49. // 继续注入其他共享数据
  50. // provideNewsStore(app);
  51. }
  52. // main.js
  53. import { createApp } from "vue";
  54. import provideStore from "./store";
  55. const app = createApp(App);
  56. provideStore(app);
  57. app.mount("#app");

示例代码

demo-provide-inject.rar

对比


vuex
global state Provide&Inject
组件数据共享
可否脱离组件
调试工具
状态树 自行决定 自行决定
量级