前端数据共享的那些事
发展历程
1,不辞辛苦的上下级组件间传递数据
<!-- parent.vue -->
<template>
<div>
<!-- 利用 js json 对象的引用方式去传递对象,然后所有子组件一起用 -->
<child :data='{ a: 1 }'></child>
</div>
</template>
<!-- child.vue -->
<template>
<div>
<!-- 子组件可以避开 vue.js 的警告对数据进行修改 -->
{{ data.a }}
</div>
</template>
评价:开发一时爽,接手火葬场!当共享对象被足够多的组件引用后,调试和定位问题将难以进行。比如:data.a 到底是被哪个组件修改的?又被改了多少次?
2,机智一点利用外部 js 文件共享数据
<!-- store.js -->
export default {
a: 1
}
<!-- anyone.vue -->
<template>
<div>
<!-- common.a 等于 1 -->
{{ common.a }}
</div>
</template>
<script>
import data from './store.js'
export default {
data() {
return {
common: data
}
}
}
</script>
评价:比 1 好一点,数据不再通过子组件传递。但问题依旧还在。
3,符合现代工程化的共享数据模式。即:flux 模型(本文将用 vuex 实现)
先简单介绍一下什么是 flux 模型?
flux 是一个“单向数据流”的思想模型,为的就是解决 1、2 两点的数据流程不清晰的问题。
这是最简单的实现方式,其中:
View:代表视图
Actions:代表操作数据的动作
State:代表状态。即:共享的数据
如图所示,这是一个单向流程的过程。不允许反悔往回走
优点:可监控、可调试(基于 vue-devtools 上)、可实现良好的项目架构(体现在使用 vuex 上)
对应的缺点:心智负担大(既要学习如何使用、还要考虑该如何配置、在项目工期赶的情况下显得回报率低,这就是为什么很多人不爱用 vuex 的原因)
技巧
1,modules (模块化)
原先的合并 common-store 的方式
// 粗暴式合并
import Vue from "vue";
import Vuex from "vuex";
import commonStore from "@/utils/common-store";
Vue.use(Vuex);
const store = {
state: {},
mutations: {}
};
for (let key in commonStore) {
store[key] = {
...store[key],
...commonStore[key]
};
}
export default new Vuex.Store(store);
现在可以通过添加 namespaced 属性并设置为 true ,就可以直接通过 this.$store.state.moduleName.xxx 引用数据
具体例子:
<!-- user.js -->
export default {
// 重点
namespaced: true,
state: {
userName: "JJ"
}
};
<!-- index.js -->
import Vue from 'vue'
import Vuex from 'vuex'
import user from './user'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
a: 1
},
mutations: {
},
actions: {
},
modules: {
user
}
})
总结:其实这种重复的配置可以用 vscode 自带的代码补全功能将 index.js 这种代码保存,在需要的时候直接一键导入即可。总之:don’t repeat your self !
2,数据模型的设计
适当的分类、尽可能的少扁平化
如表单:(visibility 可视、loading 加载等等,可以提高代码的可读性)
<!-- 修改前 -->
{
a: 1,
b: 2,
c: 3
}
<!-- 修改后 -->
{
form: {
a: 1,
b: 2,
c: 3
}
}
这么做的好处是,你处理异步提交或批量数据更新就不需要逐个引用,直接引用对象即可(data也适用)
如:
axios.post('url', $store.state.form)
<!-- 而非这样(效果立竿见影) -->
axios.post('url', {
a: $store.state.a,
b: $store.state.b,
c: $store.state.c
})
如无必要,别加新的 key 。尽量提早准备好(你的接手同事可没你清楚什么时候会多出一个 key 值哦!)
如:
<!-- 原先默认的数据 -->
{
a: 1
}
<!-- 经过一些业务代码后而添加的新数据 -->
{
a: 1,
b: 2
}
3,重置模型
为什么要配一个初始化的方法?
例如:登录后的用户、购物车 等类似较为庞大的数据,一旦用户推出登录了,该怎么快速且高效的重置这些信息?
直接上答案:
<!-- 利用放回字面量对象的方式快速生成一个全新对象 -->
function defaultState() {
return {
userName: "",
userId: "",
dealerId:"",
dealerName:"",
accessToken: "",
isShowSignInOrSignUpDialog: false,
dealerId: "",
role: ""
};
}
const state = defaultState();
const mutations = {
resetState(state) {
Object.assign(state, defaultState());
}
};
const actions = {};
export default {
namespaced: true,
state,
mutations,
actions
};
4,持久化数据
store 数据一旦遇到页面刷新就会被清空,这种情况下,建议用 vuex-persistedstate 解决。(可以选择保存到 local、sessionStorage、cookies 上)
原理:利用 vuex 的 subscribe 去监听一切的数据变化。并将数据保存在本地上
subscribe api 说明:https://vuex.vuejs.org/zh/api/#subscribe
实践
1,vue-devTools 的 Time Traveling 查询数据修改情况
如图所示,这里可以看到state的修改情况,甚至可以回到某一个特定的状态上进行调试
当然,也可以修改 store 和 data 里的数据。
题外话:actions 和 mutations 的区别?
一句话总结:在 Vuex 中,mutation 都是同步事务,而 actions 是用于处理异步任务的并最后通过 mutations 去修改状态。其实 mutations 中使用异步方法也可以,但就是 vue-devTools 无法监听到其中的数据变化。
2,关于减少共享数据的引用长度(即:何时使用 mapXXX 方法)
常用的 store 属性 我个人建议是挂载到 vue 实例上,其次再用 mapState 做扩展 到 computed 上(讲真,这真的很麻烦,我也没这个耐心去做)
一句话:嫌烦要经常用 . 去引入数据就用 mapXXX ,否则直接引用吧。
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!