博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
详解 Vue & Vuex 实践
阅读量:4086 次
发布时间:2019-05-25

本文共 6453 字,大约阅读时间需要 21 分钟。

翻译自,承接自,从属于。

随着应用复杂度的增加,我们需要考虑如何进行应用的状态管理,将业务逻辑与界面交互相剥离,详细讨论参考笔者的。Vue 为我们提供了方便的组件内状态管理的机制,下面这个例子就是常见的获取列表数据然后渲染到界面中:

import axios from 'axios'export default {  name: 'projects',  data: function () {    return {      projects: []    }  },  methods: {    loadProjects: function () {      axios.get('/secured/projects').then((response) => {        this.projects = response.data      }, (err) => {        console.log(err)      })    }  },  mounted: function () {    this.loadProjects()  }}

在 template 中我们可以方便的访问项目列表并且进行过滤、排序等操作,不过如果我们在另一个列表中也需要来展示相同的数据信息,继续按照这种方式实现的话我们不得不重新加载一遍数据。更麻烦的是如果用户在本地修改了某个列表数据,那么如何同步两个组件中的列表信息会是个头疼的问题。Vue 官方推荐使用,类似于 Redux 的集中式状态管理工具来辅助解决这个问题。

何谓 Vuex?

根据  文档中的描述,Vuex 是适用于 Vue.js 应用的状态管理库,为应用中的所有组件提供集中式的状态存储与操作,保证了所有状态以可预测的方式进行修改。

Vuex 中 Store 的模板化定义如下:

import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({  state: {  },  actions: {  },  mutations: {  },  getters: {  },    modules: {      }})export default 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 引入项目中:

$ yarn add vuex

该步骤完成之后,我们需要在 src 目录下创建名为 store 的目录来存放状态管理相关代码,首先创建 index.js:

import Vue from 'vue'import Vuex from 'vuex'import axios from 'axios'Vue.use(Vuex)const store = new Vuex.Store({  state: {  },  actions: {  },  mutations: {  },  getters: {  }})export default store

然后在 main.js 文件中我们需要将该 Store 实例添加到构造的 Vue 实例中:

import store from './store'/* eslint-disable no-new */new Vue({  template: `  
`, router, store, components: { navbar }}).$mount('#app')

然后,我们需要去完善 Store 定义:

import Vue from 'vue'import Vuex from 'vuex'import axios from 'axios'Vue.use(Vuex)const store = new Vuex.Store({  state: {    projects: []  },  actions: {    LOAD_PROJECT_LIST: function ({ commit }) {      axios.get('/secured/projects').then((response) => {        commit('SET_PROJECT_LIST', { list: response.data })      }, (err) => {        console.log(err)      })    }  },  mutations: {    SET_PROJECT_LIST: (state, { list }) => {      state.projects = list    }  },  getters: {    openProjects: state => {      return state.projects.filter(project => !project.completed)    }  }})export default store

在本项目中,我们将原本存放在组件内的项目数组移动到 Store 中,并且将所有关于状态的改变都通过 Action 进行而不是直接修改:

// /src/components/projectList.vue

这个模板还是十分直观,我们通过computed对象来访问 Store 中的状态信息。值得一提的是这里的mapState函数,这里用的是简写,完整的话可以直接访问 Store 对象:

computed: {  projects () {    return this.$store.state.projects  }}

mapState 是 Vuex 提供的简化数据访问的辅助函数。我们视线回到 project.vue 容器组件,在该组件中调用this.$store.dispatch('LOAD_PROJECT_LIST)来触发从服务端中加载项目列表:

当我们启动应用时,Vuex 状态管理容器会自动在数据获取之后渲染整个项目列表。现在我们需要添加新的 Action 与 Mutation 来创建新的项目:

// under actions:ADD_NEW_PROJECT: function ({ commit }) {  axios.post('/secured/projects').then((response) => {    commit('ADD_PROJECT', { project: response.data })  }, (err) => {    console.log(err)  })}// under mutations:ADD_PROJECT: (state, { project }) => {  state.projects.push(project)}

然后我们创建一个简单的用于添加新的项目的组件 addProject.vue:

该组件会派发某个 Action 来添加组件,我们需要将该组件引入到 projects.vue 中:

重新运行下该应用会看到服务端返回的创建成功的提示,现在我们添加另一个功能,就是允许用户将某个项目设置为已完成。我们现在添加新的组件 completeToggle.vue:

该组件会展示一个用于切换项目是否完成的按钮,我们通过 Props 传入具体的项目信息然后通过触发 TOGGLE_COMPLETED Action 来使服务端进行相对应的更新与相应:

// actionsTOGGLE_COMPLETED: function ({ commit, state }, { item }) {  axios.put('/secured/projects/' + item.id, item).then((response) => {    commit('UPDATE_PROJECT', { item: response.data })  }, (err) => {    console.log(err)  })}// mutationsUPDATE_PROJECT: (state, { item }) => {  let idx = state.projects.map(p => p.id).indexOf(item.id)  state.projects.splice(idx, 1, item)}

UPDATE_PROJECT 会触发项目列表移除对应的项目并且将服务端返回的数据重新添加到数组中:

app.put('/secured/projects/:id', function (req, res) {  let project = data.filter(function (p) { return p.id == req.params.id })  if (project.length > 0) {    project[0].completed = !project[0].completed    res.status(201).json(project[0])  } else {    res.sendStatus(404)  }})

最后一步就是将 completeToggle 组件引入到 projectList 组件中,然后将其添加到列表中:

// new column in table
// be sure import and add to the components object

再谈引入状态管理的意义

现在我们的应用已经具备了基本的特性,这里我们再度回顾下文首的讨论,为什么我们需要大费周章的引入外部状态管理,将业务逻辑切分到组件外。譬如这里我们需要另一个组件来展示项目的统计信息,譬如项目的总数或者已完成项目的数目。我们肯定要避免重复地从服务端抓取数据,而是所谓的 Single Source Of Truth。这里我们添加新的 projectStatus.vue 组件来展示项目的统计信息:

该组件会展示项目的总数与已完成项目的总数,上面我们使用了maoGetters辅助函数来减少冗余代码:

getters: {  completedProjects: state => {    return state.projects.filter(project =>project.completed).length  },  projectCount: state => {    return state.projects.length  }}

最后我们将该统计信息添加到项目列表中,效果图示如下:

转载地址:http://hzeni.baihongyu.com/

你可能感兴趣的文章
React Native for Android 发布独立的安装包
查看>>
React Native应用部署/热更新-CodePush最新集成总结(新)
查看>>
react-native-wechat
查看>>
基于云信的react-native聊天系统
查看>>
网易云音乐移动客户端Vue.js
查看>>
ES7 await/async
查看>>
ES7的Async/Await
查看>>
React Native WebView组件实现的BarCode(条形码)、(QRCode)二维码
查看>>
每个人都能做的网易云音乐[vue全家桶]
查看>>
JavaScript专题之数组去重
查看>>
Immutable.js 以及在 react+redux 项目中的实践
查看>>
Vue2.0全家桶仿腾讯课堂(移动端)
查看>>
React+Redux系列教程
查看>>
react-native 自定义倒计时按钮
查看>>
19 个 JavaScript 常用的简写技术
查看>>
ES6这些就够了
查看>>
微信小程序:支付系列专辑(开发指南+精品Demo)
查看>>
iOS应用间相互跳转
查看>>
iOS开发之支付宝集成
查看>>
iOS开发 支付之银联支付集成
查看>>