共享数据的方式
三种方案
- vuex方案
- global state 方案
- provide&inject 方案
vuex方案
安装vuex@4.x
两个重要变动:
- 去掉了构造函数
Vuex
,而使用createStore
创建仓库 - 为了配合
composition api
,新增useStore
函数获得仓库对象import * as userServ from "../api/user";
export default {
namespaced: true,
state: {
user: null,
loading: false,
},
mutations: {
setUser(state, payload) {
state.user = payload;
},
setLoading(state, payload) {
state.loading = payload;
},
},
actions: {
async login({ commit }, { loginId, loginPwd }) {
commit("setLoading", true);
const user = await userServ.login(loginId, loginPwd);
commit("setUser", user);
commit("setLoading", false);
return user;
},
async loginOut({ commit }) {
commit("setLoading", true);
await userServ.loginOut();
commit("setUser", null);
commit("setLoading", false);
},
async whoAmI({ commit }) {
commit("setLoading", true);
const user = await userServ.whoAmI();
commit("setUser", user);
commit("setLoading", false);
},
},
};
示例代码
demo-vuex.rarglobal state
由于vue3
的响应式系统本身可以脱离组件而存在,因此可以充分利用这一点,轻松制造多个全局响应式数据
```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; }
<a name="GOhkh"></a>
### 示例代码
[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)
<a name="0fI9W"></a>
# Provide&Inject
在`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`方法,用于提供整个应用的共享数据
```vue
creaetApp(App)
.provide("foo", ref(1))
.provide("bar", ref(2))
.mount("#app");
因此,我们可以利用这一点,在整个vue应用中提供共享数据
// 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");
示例代码
对比
vuex |
global state | Provide&Inject | |
---|---|---|---|
组件数据共享 | ✅ | ✅ | ✅ |
可否脱离组件 | ✅ | ✅ | ❌ |
调试工具 | ✅ | ❌ | ✅ |
状态树 | ✅ | 自行决定 | 自行决定 |
量级 | 重 | 轻 | 轻 |