// new column in table
<td><complete-toggle :item="item" /></td>
// be sure import and add to the components object
再谈引入状态管理的意义
现在我们的应用已经具备了基本的特性,这里我们再度回顾下文首的讨论,为什么我们需要大费周章的引入外部状态管理,将业务逻辑切分到组件外。譬如这里我们需要另一个组件来展示项目的统计信息,譬如项目的总数或者已完成项目的数目。我们肯定要避免重复地从服务端抓取数据,而是所谓的 Single Source Of Truth。这里我们添加新的 projectStatus.vue 组件来展示项目的统计信息:
详解 Vue & Vuex 实践 - 知乎
首发于某熊的技术之路
关注专栏写文章
详解 Vue & Vuex 实践
王下邀月熊
王下邀月熊
116 人赞了该文章
随着应用复杂度的增加,我们需要考虑如何进行应用的状态管理,将业务逻辑与界面交互相剥离,详细讨论参考笔者的2016-我的前端之路:工具化与工程化。Vue 为我们提供了方便的组件内状态管理的机制,下面这个例子就是常见的获取列表数据然后渲染到界面中:
在 template 中我们可以方便的访问项目列表并且进行过滤、排序等操作,不过如果我们在另一个列表中也需要来展示相同的数据信息,继续按照这种方式实现的话我们不得不重新加载一遍数据。更麻烦的是如果用户在本地修改了某个列表数据,那么如何同步两个组件中的列表信息会是个头疼的问题。Vue 官方推荐使用Vuex,类似于 Redux 的集中式状态管理工具来辅助解决这个问题。
何谓 Vuex?
根据 Vuex 文档中的描述,Vuex 是适用于 Vue.js 应用的状态管理库,为应用中的所有组件提供集中式的状态存储与操作,保证了所有状态以可预测的方式进行修改。
Vuex 中 Store 的模板化定义如下:
上述代码中包含了定义 Vuex Store 时关键的 5 个属性:
state: state 定义了应用状态的数据结构,同样可以在这里设置默认的初始状态。
state: { projects: [], userProfile: {} }
actions:Actions 即是定义提交触发更改信息的描述,常见的例子有从服务端获取数据,在数据获取完成后会调用store.commit()来调用更改 Store 中的状态。可以在组件中使用dispatch来发出 Actions。
actions: { LOAD_PROJECT_LIST: function ({ commit }) { axios.get('/secured/projects').then((response) => { commit('SET_PROJECT_LIST', { list: response.data }) }, (err) => { console.log(err) }) } }
mutations: 调用 mutations 是唯一允许更新应用状态的地方。
mutations: { SET_PROJECT_LIST: (state, { list }) => { state.projects = list } }
getters: Getters 允许组件从 Store 中获取数据,譬如我们可以从 Store 中的 projectList 中筛选出已完成的项目列表:
getters: { completedProjects: state => { return state.projects.filter(project => project.completed).length } }
modules: modules 对象允许将单一的 Store 拆分为多个 Store 的同时保存在单一的状态树中。随着应用复杂度的增加,这种拆分能够更好地组织代码,更多细节参考这里。
Example
在理解了 Vuex 的基础概念之后,我们会创建一个真正的应用来熟悉整个使用流程。该应用承接自这个博客,在准备好基础项目之后,我们需要将 vuex 引入项目中:
该步骤完成之后,我们需要在 src 目录下创建名为 store 的目录来存放状态管理相关代码,首先创建 index.js:
然后在 main.js 文件中我们需要将该 Store 实例添加到构造的 Vue 实例中:
然后,我们需要去完善 Store 定义:
在本项目中,我们将原本存放在组件内的项目数组移动到 Store 中,并且将所有关于状态的改变都通过 Action 进行而不是直接修改:
这个模板还是十分直观,我们通过computed对象来访问 Store 中的状态信息。值得一提的是这里的mapState函数,这里用的是简写,完整的话可以直接访问 Store 对象:
mapState 是 Vuex 提供的简化数据访问的辅助函数。我们视线回到 project.vue 容器组件,在该组件中调用this.$store.dispatch('LOAD_PROJECT_LIST)来触发从服务端中加载项目列表:
当我们启动应用时,Vuex 状态管理容器会自动在数据获取之后渲染整个项目列表。现在我们需要添加新的 Action 与 Mutation 来创建新的项目:
然后我们创建一个简单的用于添加新的项目的组件 addProject.vue:
该组件会派发某个 Action 来添加组件,我们需要将该组件引入到 projects.vue 中:
重新运行下该应用会看到服务端返回的创建成功的提示,现在我们添加另一个功能,就是允许用户将某个项目设置为已完成。我们现在添加新的组件 completeToggle.vue:
该组件会展示一个用于切换项目是否完成的按钮,我们通过 Props 传入具体的项目信息然后通过触发 TOGGLE_COMPLETED Action 来使服务端进行相对应的更新与相应:
UPDATE_PROJECT 会触发项目列表移除对应的项目并且将服务端返回的数据重新添加到数组中:
最后一步就是将 completeToggle 组件引入到 projectList 组件中,然后将其添加到列表中:
再谈引入状态管理的意义
现在我们的应用已经具备了基本的特性,这里我们再度回顾下文首的讨论,为什么我们需要大费周章的引入外部状态管理,将业务逻辑切分到组件外。譬如这里我们需要另一个组件来展示项目的统计信息,譬如项目的总数或者已完成项目的数目。我们肯定要避免重复地从服务端抓取数据,而是所谓的 Single Source Of Truth。这里我们添加新的 projectStatus.vue 组件来展示项目的统计信息:
该组件会展示项目的总数与已完成项目的总数,上面我们使用了maoGetters辅助函数来减少冗余代码:
最后我们将该统计信息添加到项目列表中,效果图示如下:
发布于 2017-01-29
[
Vue.js
](//www.zhihu.com/topic/20022242)
[
Vuex
](//www.zhihu.com/topic/20044614)
赞同 11623 条评论
分享
收藏
文章被以下专栏收录
[
](/wxyyxc1992)
[
某熊的技术之路
](/wxyyxc1992)
让知识在它该在的地方
进入专栏
推荐阅读
[
Vue2 后台管理系统解决方案
林鑫
](https://zhuanlan.zhihu.com/p/25586613)[
简单强大的VUE分页组件
最近项目组在使用vue框架,ui组件库使用element-ui,我也好好学习了一遍。封装了一下表格的分页组件给项目组使用,个人觉得封装得相当不错,使用也简单满足绝大部分场景,特分享给大家:) …
晓风轻
](https://zhuanlan.zhihu.com/p/31638307)[
vue.js+flask+element-ui简易Demo
气势的信心
](https://zhuanlan.zhihu.com/p/29429149)[
Vue.js起手式+Vue小作品实战
Teren
](https://zhuanlan.zhihu.com/p/24536535)
23 条评论
切换为时间排序
写下你的评论...
发布
yeatszhang2 年前
最近科普入门性质的文章较多啊~
赞回复踩举报
王下邀月熊 (作者) 回复yeatszhang2 年前
是哒,好歹要对得起这个新年
赞回复踩举报
知乎用户2 年前
写得很清晰,看了官网的文档,感觉一头雾水,看了你这篇文章,感觉变清晰了
赞回复踩举报
Deboy2 年前
得益于 vue2.x + vuex2.x 更为便捷的API,更容易上手和理解了,1.0的即使看懂了 API ,也有种难以下手的感觉
赞回复踩举报
YeaseonZhang2 年前
提个小建议,代码没有语法高亮
1回复踩举报
Archer2 年前
有没有源码学习?
1回复踩举报
lbca2 年前
不错!
赞回复踩举报
知乎用户1 年前
可以 的
赞回复踩举报
蓝月萧枫1 年前
问个问题,使用vuex的页面中,如何处理页面列表搜索的问题?
比如页面要做个快速匹配列表项的功能,列表内容映射自vuex中的state,这里列表内容只向服务器请求一次,vuex是不推荐直接在组中改变state值的,而列表的值响应匹配到的值,对于这样你是怎么解决呢?
我说下我的方法:我一般是请求获得列表数据后复制一份在state.originData ,列表绑定的是state.data 然后匹配操作在ations中用state.originData数据来操作,然后触发mutations更新state.data来达到目的,但是总感觉有点麻烦,也不知道这样合理不合理
1回复踩举报
dongdong1 年前
对于刚接触vuex的人来说,简单易懂,好文章
赞回复踩举报
知乎用户1 年前
maoGetters -> mapGetters
1回复踩举报
一笑1 年前
作者好,看了你的文章,感觉收获很多。不过在自己尝试开发的过程中遇到一个问题,当页面渲染一个20 * 30,页面上大部分表格单元都要绑定事件来显示tooltip的时候,在路由跳转的时候就会变得很慢,这是什么原因呢?事件绑定过多?有没有什么解决的办法?
赞回复踩举报
弗洛伊德-凯1 年前
dispatch 在2.0下还可以用吗
赞回复踩举报
LowLoop1 年前
简单明了+1.
赞回复踩举报
姜真1 年前
作者有一个地方好像写错了,计算属性那里不能用mapState,mapState返回的是一个对象,是把全局的 state 和 getters 映射到当前组件的 computed 计算属性中,因此v-for不能迭代出来,应该用mapGetters。我也是学习作者的文章,结果在这里卡了好久,已经从服务器拿到数据,但就是显示不出来,研究了好久才发现是这个问题,希望可以帮后面的同学少走点弯路
2回复踩举报
xiaoy回复姜真11 个月前
你好,你的解释是我在这里看到最好的,我想问下,你从服务拿数据应该是在以node做服务,我能参考下你之前写的源码吗
赞回复踩举报
丁一1 年前
在vuex理处理局部数据应该是不合适的,全局vuex和局部数据能否有和谐统一的方式进行处理?
赞回复踩举报
黑糖冬瓜露1 年前
我NG和RN,现在学Vue,看完整篇感觉写的非常好,赞一个!
赞回复踩举报
诗酒趁年华1 年前
谢谢楼主无私分享
赞回复踩举报
xiaoy11 个月前
真的想看看你的源码是如何写的
赞回复踩举报
xiaoy11 个月前
好急呀,急得看源码,你这边的node处理是写在哪里的,看的人真的很急
赞回复踩举报
芒果11 个月前
分享个vuex 2的教程 Vuex2入门与提高_vue.js教程_汇智网)
赞回复踩举报
12下一页
想来知乎工作?请发送邮件到 jobs@zhihu.com