vue

✍️ Tangxt ⏳ 2020-09-29 🏷️ vuex

12-Vue 全局数据管理(下)之 Vuex

★Vuex 初体验 - 数据读写

全局数据管理

1)安装

安装 vuex (在创建项目的时候我们已经安装了),如果没有那就 npm 一下呗!

2)是什么?

是什么

我们在写文章的时候 -> 记住不要用那么多术语

话又说回来,我们该如何理解 vuex 是什么呢?

用之前我们弄得 store 来理解它 -> 用来管理数据的工具! -> 简单来说,它就是个对象,提供了一些 API,让我们可以读数据(查)和写数据(增删改)!

总之,所谓「管理」就是「读写」,所谓「状态」就是「数据」! -> 「状态管理模式」即是「数据读写工具」(关于「模式」的解释,芳芳也不知道是什么意思……)

3)我们能否透过官方提供的视频学会 vuex ?

视频 1视频 2

vuex

很难 -> 因为对于中国人而言,它是英文教学的 -> 所以我们只好用 CRM 大法看官方文档学习它了!

很多时候我们学不会某个东西,并不是因为我们的智商问题,而是入门教程实在太辣鸡了!

代码:Demo

💡:store可不是那个参数{}

store

我们传的state显然是复制到了store这个实例上! -> 跟我们之前...tagStore一样……

💡:你以为在state里边不能写方法吗?

方法也可写

💡:读写状态的操作?

data即是statemethods即是mutations -> Vue 很贱,总是发明一些新的单词来增加我们的记忆负担! -> 其实是延用了某些设计才搞得这些新单词!

进一步分析一下「写」:

不要用 this

this可能是window

不要用this哈,如果你用了,那也是白用了! -> 传个state形参,然后state.count += 1这样改!

如何调用increment方法?

显然不会用这种智障姿势:

store.mutations.increment(store.state)

vuex 给我们封装了一个 API:

// 不需要我们自己传 state 参数!
store.commit('increment')

讽刺:Vuex 给了我们非常多的新单词,但这些单词只是换汤不换药! -> 本来数据叫data的,现在则是叫state,本来改变数据直接调用increment就好了,但现在不能直接调,而是透过commit提交一下'increment'方法名来调!

💡:vuex 真得比我们之前封装的store好用吗?

store

没有好用到哪儿去! -> vuex 改变了我们操作数据的姿势!

💡:如何给mutation传参?(如何给改动数据的 API 传参?)

传参

有的时候,如果你代码写得不好,那么你就去发明概念,你概念发明好了,然后写一些非常简单的库,也可以让这些「简单的」库看起来变得非常牛逼!

我很菜,但我可以捣鼓一些你不懂的概念,让我看起来很牛逼,很高级!

💡:单一状态树是什么?

简单来说就是对象(包含了全部的应用层级状态)

{
  state: {
    count: 0,
    user: {
      name: 'frank',
      age: 18
    }
  }
}

所谓的树 -> 数据的嵌套层级很深,看起来像是一棵树!

应用层级状态 -> 应用就是「你的这个项目」、层级就是「一层层的组件」,毕竟一个项目是由很多个组件组合而成的、状态即「数据」 -> 合起来就是「你的项目里边所有组件的数据」 -> 不说人话的解释就是「应用层级状态」

唯一数据源 -> 我们整个应用没有第二个数据,那就叫做唯一数据源!

为了权威性,所以增加了很多术语,但其实没啥用呀! -> 真正学习编程,一定要了解这个东西的本质才行! -> store本质就是一个对象!

💡:单一状态树让我们能够直接地定位任一特定的状态片段?

我们可以获取全局对象里边的任意一个数据片段,如count

💡:单状态树和模块化并不冲突?

模块化

就是分文件呗!

💡:如何在组件中获取状态?

需要计算属性 -> 计算属性写在@Component这个装饰器里边!

computed

如果你只想用一次,那就用data姿势呗!但大部分情况都不止用一次哈!

总之,count会计算依赖 -> store.state.count变了,那么count就会变!

💡:template里边可以拿到importstore吗?

不能

如何解决?

很简单,你改成是一个函数名不就行了:

做法

另一种解决姿势:

代码

Vue.use(Vuex)这行代码,use操作会去调用Vuex里边的一些东西,这些东西会在Vue的原型上绑定一些共用属性!

Vue.use(Vuex)就是在安装这个Vuex插件,也就是为Vue.prototype挂载一个$store属性! -> 也就是把 store 给绑定了: Vue.prototype.$store = store

当我们:

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");

这样做时,就是传一个store$store了!

话说,为啥不在index.ts里边一开始就传了?而是跑去main.ts里边传? -> 就是这样设计的!因为符合初始化语法哈! -> 相当于是注册了,要初始化才能使用!

所以另一种姿势就这样这样:

另一种姿势

💡:计算属性与data同名,你猜template里边会渲染谁?

data 先吃

'[Vue warn]: The computed property "recordList" is already defined in data.'

4)小结

使用$store不需要我们import store

对比我们之前写的自定义store,vuex 并没有好在哪里,而且很不简洁!(很复杂) -> 也比不上那种window姿势! -> 明明使用 vuex 没有好处,为啥还要学呢? -> 因为大家都在学呗! -> 前端的整体水平有待提高,毕竟什么是好处,什么是坏处,一点深刻认识都没有!

批判一个东西前先学会它,不然,别人是不信你所说的!

★在 Money.vue 中使用 Vuex

action是用来调用method的 -> 异步操作! -> 旺财升级版会用到它!

1)改代码

  1. 删掉所有import index2 的代码!(我没有这样做,我是一个组件一个组件这样慢慢改……)
  2. 处理fetchRecords -> createRecord -> saveRecords

爆红波浪线处理

代码:Demo

💡:注释是给初学者看的,作为同行不需要看,所以把代码里边存在的注释都给删咯!

💡:改用 vuex,那么就有意去削掉methods里边的this

state

可以用this,但就是让你不要用!

💡:改代码时,步子不要迈得太大

如,方方一开始就把所有的import index2都给删了! -> 这样每次测试是否把代码修改成功都会报错!

💡:关于注释:// TODO

todo

todo意味着你之后要去修改代码的,而且如果遗漏了 todo 没有完成,那么在你提交代码时,会告诉你这个:

todo

你可以 review 一下看看有哪些 todo,也可以不管未完成的todo,直接 commit

💡:mutations里边的方法都有返回值吗?

是没有的,直接改state里边的数据就行了!

返回值

★重构 Tags.vue 和 Labels.vue

1)重构 Tags.vue

mutations里边添加方法 -> 每个方法总是需要传state这个形参!

代码:Demo

如果一开始就用 Vuex ,那就不用改代码了,但是这样一来,就不能更好地理解 Vuex 了!

2)重构 Labels.vue

💡:一定要重复fetch

Tags.vue需要fetchLabels.vue也需要fetch -> 因为如果只有Tags.vuefetch,那么你直接刷新Labels.vue是拿不到TagList的,因为Tags.vue还没有渲染呢,以致于全局state还咩有拿到值……

每次切换路由所对应的组件都会重新fetch -> 牺牲点性能,保证每次拿到的都是最新的数据!

每次切换路由 -> 意味着切换组件 -> 意味着每次都会执行created钩子!

💡:出现两次一模一样的代码?

重复两次

代码重复出现两次,可优化亦可不优化! -> 如果优化,那就用 mixin 呗!

★在 TS 里使用 mixin(重新上传)

mixin很好用,它可以把多个组件都用到的方法收拢到一个组件里边 -> 需要mixin的组件extends一下mixins就好了!

1)使用 mixin

  1. 创建/src/mixins/createTags.js -> 为啥加s,因为src目录下大多有多个加s的目录,简单来说,我们可能不止会用到一个mixin
  2. mixins是个对象,直接导出就好了 -> 为啥不是.ts文件? -> 因为有this会报错!而用.js则不会报错!

代码:Demo

💡:名字修改?

在组件里边使用mixin时,我们导入的是这个mixin的文件名

名字

我们改成是tagHelper.js了,如果是类,那就是大写TagHelper,而对象则是小写!

💡:如何禁用 Eslint 对某一行代码报错?

自己谷歌搜! -> 在 ts 里边使用 js,Eslint 可能无法通过!

💡:在写代码的过程中,发现往 ts 里边 混入 js 代码,是危险的操作?

一个js文件,会污染整个用 ts 写的项目!

js

但如果改成 ts,又得报错了:

ts

我们用的类组件,是使用第三方工具的,而这个第三方工具也是依赖官方所提供的Vue Class Component的,在 官网 里边我们找到「如何配合ts使用mixin

过程挺麻烦的 -> 你选择了使用 ts,那就相当于选择了一条高端之路!

做法 -> 把mixin声明成类组件 -> 这意味我们的文件名要改成大写的TagHelper了!

名字

这个名字问题 -> 如果xxx组件也有同一个叫create的方法,那么就会被覆盖了!

题外话:

mixin

★重构 EditLabel.vue

重构知识点

1)重构

代码:Demo

💡:commit的返回值是void

返回值

如何拿到我们要的返回值?

返回值

tag 初始值的原因:

tag 初始值

因为我们原本就是这样做的!

★在 TS 里使用 computed 要用 getter 语法

TS & Vue

如何解决?

  1. 搜索 vue-property-decorator 的文档 -> 发现咩有答案
  2. 搜索 Vue Class Component 的文档 -> 找到了答案 -> 用原生自带的getset函数来写计算属性(写在 class 里边),而不是把computed作为一个选项传给@Component这个注解!

解决 bug

用了 TS,那么你就得严谨看待 -> 不要看到报错,就改成是 JS 的 -> 你要把网上能搜索的资料(不管是英文还是中文)都给测试一遍 -> 排除法,解决 bug!

对了,除了这个EditLabel.vue需要用到computed,其它的组件也用到了,如果你不想你的代码成为屎山,那么你就把之前写的computed,改成是get姿势的! -> 千万不要认为这样很费时间!

改法(全局搜索用到computed.vue文件):

改法

代码:Demo

关于set,我们没有用到 -> 所以就不用管了!

💡:是否用了get之后,所拿到的值也会有缓存的效果?

是的,因为计算属性本质上就是一个由getter/setter作为键值的对象

★继续重构 EditLabel.vue

知识点

1)处理 `updateTag` & `removeTag`

💡:莫名其妙的报错?

报错

我们是如何找到错误原因的?

先把函数体里边的代码给注释了 -> 传一个state参数试试报不报错? -> 不报错 -> 传第一个参数试试报不报错? -> 不报错 -> 传第三个参数试试报不报错? -> 报错了!

所以可以看到,写在mutations里边的方法只能接受一个参数 -> 所以我们把参数改成是对象形式的即可解决之!

updateTag(state, object: { id: string, name: string }) {}

注意,一般我们管接收参数的形参叫playload

💡:一个 bug,对用户 input的值同时用了 watcher@input

会触发两次操作! -> 我们只需要触发一次! -> 如果有单元测试会好很多!

💡:VS Code 在重构变量名时是通过字符串匹配改的,而 webstorm 则是透过语义来改的!

如你打log的参数字符串里边有你要改的字符,那么 VS Code 也会把它给改了!

💡:Vuex 的弊端?

commit的时候,如果传的字符串方法名参数写错了,那么它是不会报错的!

💡:用户重新刷新页面的问题?

页面刷新


以后的数据读和写,都透过$store来搞! -> 有点麻烦 -> 但还是有小技巧,让我们不用这样做的! -> 总之,先把思路给走通咯!

接下来总结一下使用 Vuex 的常用套路!

★Vuex 总结(后续课程还有更多总结)

1)使用 Vuex 的常用套路

💡:安装Vuex

  1. Vue.use(Vuex) -> 安装
  2. new Vue({store}) -> 初始化 -> 让我们可以this.$store

💡:定义store

定义

💡:如何组件里边使用store

分为读和写:

读和写

💡:更厉害的旺财项目?

会用到 actions 这个选项! -> 不用听方方讲,直接用 CRM 大法看文档学习就好了,毕竟经历过方方的系统课程之后,就没有什么新知识了


全局状态管理 -> Vue 就 Vuex 这么一个方案 -> 我们只用了本地数据管理,没有用异步操作获取远程数据,所以也就没有用actions了!

接下来完成「统计页面」!

★总结

★Q&A

1)什么是纯粹的对象?

问题缘由:

纯粹的

State - Vuexdata — Vue.js

什么是存粹的对象?

我们 var obj = {} 相当于是执行了这个语句:

var obj = Object.create(Object.prototype)

这个 obj 是不存粹的,因为它生来自带了Object的一系列内置属性和方法

如何才能造个存粹的对象?

很简单,直接这样:

var obj = Object.create(null)

纯粹的对象

为什么需要纯粹的对象?

「纯粹」的对象适合用于存储键值对数据,而且没有隐式的类型转换,更加直观

总之,除了继承了Object.prototype这点,Object.create(null){}之间没有别的区别了,在操作对象这一点上完全一致,存取的性能没差啦。但如果并不 care 自己的空对象继承了Object的话,我建议大家还是使用{}来声明吧,因为在创建性能上{}Object.create(null) 快了 20 倍呢!!!

➹:什么是纯粹的 JS 对象?? - 简书

2)Vue 的 `use` 方法?

➹:Vue.use(plugin) 详解