vuex 方案
pinia 方案
global state
由于
vue3
的响应式系统本身可以脱离组件而存在,因此可以充分利用这一点,轻松制造多个全局响应式数据
-
图解
-
示例代码
// 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
-
在
vue2
中,提供了provide
和inject
配置,可以让开发者在高层组件中注入数据,然后在后代组件中使用;
-
除了兼容
vue2
的配置式注入,vue3
在composition api
中添加了provide
和inject
方法,可以在setup
函数中注入和使用数据;
-
考虑到有些数据需要在整个 vue 应用中使用,
vue3
还在应用实例中加入了provide
方法,用于提供整个应用的共享数据;
creaetApp(App) .provide("foo", ref(1)) .provide("bar", ref(2)) .mount("#app");
-
因此,可以利用这一点,在整个 vue 应用中提供共享数据
JavaScriptJavaScriptJavaScriptHTML// 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 | |
---|---|---|---|
组件数据共享 | ✅ | ✅ | ✅ |
可否脱离组件 | ✅ | ✅ | ❌ |
调试工具 | ✅ | ❌ | ✅ |
状态树 | ✅ | 自行决定 | 自行决定 |
量级 | 重 | 轻 | 轻 |
vue3🛫 Suspense 组件
上一篇