vuex 方案

pinia 方案

global state

由于 vue3 的响应式系统本身可以脱离组件而存在,因此可以充分利用这一点,轻松制造多个全局响应式数据

  1. 图解

  2. 示例代码

    // 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;
    }
    

Provide & Inject

  1. vue2 中,提供了 provideinject 配置,可以让开发者在高层组件中注入数据,然后在后代组件中使用;

  2. 除了兼容 vue2 的配置式注入,vue3composition api 中添加了 provideinject 方法,可以在 setup 函数中注入和使用数据;

  3. 考虑到有些数据需要在整个 vue 应用中使用,vue3 还在应用实例中加入了 provide 方法,用于提供整个应用的共享数据;

    creaetApp(App)
      .provide("foo", ref(1))
      .provide("bar", ref(2))
      .mount("#app");
    
  4. 因此,可以利用这一点,在整个 vue 应用中提供共享数据

    JavaScript
    JavaScript
    JavaScript
    HTML
    // store/useLoginUser 提供当前登录用户的共享数据
    import { readonly, reactive, inject } from "vue";
    const key = Symbol(); // Provide 的 key
    
    // 在传入的 vue 应用实例中提供数据
    export function provideStore(app) {
      // 创建默认的响应式数据
      const state = reactive({ user: null, loading: false });
      // 登录
      async function login(loginId, loginPwd) {
        state.loading = true;
        const user = await userServ.login(loginId, loginPwd);
        state.loginUser = user;
        state.loading = false;
      }
      // 退出
      async function loginOut() {
        state.loading = true;
        await userServ.loginOut();
        state.loading = false;
        state.loginUser = null;
      }
      // 恢复登录状态
      async function whoAmI() {
        state.loading = true;
        const user = await userServ.whoAmI();
        state.loading = false;
        state.loginUser = user;
      }
      // 提供全局数据
      app.provide(key, {
        state: readonly(state), // 对外只读
        login,
        loginOut,
        whoAmI,
      });
    }
    
    export function useStore(defaultValue = null) {
      return inject(key, defaultValue);
    }
    
    // store/index
    // 应用所有 store
    import { provideStore as provideLoginUserStore } from "./useLoginUser";
    // 继续导入其他共享数据模块...
    // import { provideStore as provideNewsStore } from "./useNews"
    
    // 提供统一的数据注入接口
    export default function provideStore(app) {
      provideLoginUserStore(app);
      // 继续注入其他共享数据
      // provideNewsStore(app);
    }
    
    // main.js
    import { createApp } from "vue";
    import provideStore from "./store";
    const app = createApp(App);
    provideStore(app);
    app.mount("#app");
    
    <!-- app.vue -->
    <template>
      <div id="nav">
        <router-link to="/">Home</router-link> |
        <span v-if="state.loading">loading...</span>
        <template v-else-if="state.user">
          <span>{{ state.user.name }}</span>
          <a class="ml-5" href="" @click.prevent="handleLoginOut">退出</a>
        </template>
        <router-link v-else to="/login">Login</router-link>
      </div>
      <router-view />
    </template>
    
    <script>
    import { useStore } from "./store/useLoginUser";
    import { useRouter } from "vue-router";
    export default {
      setup() {
        const store = useStore();
        store.whoAmI();
    
        const router = useRouter();
        const handleLoginOut = async () => {
          await store.loginOut();
          router.push("/login");
        };
        
        return {
          ...store,
          handleLoginOut,
        };
      },
    };
    </script>
    

对比

vuex global state Provide&Inject
组件数据共享
可否脱离组件
调试工具
状态树 自行决定 自行决定
量级
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. vuex 方案
  2. 2. pinia 方案
  3. 3. global state
  4. 4. Provide & Inject
  5. 5. 对比