对vuex工作流程的理解

1,487 阅读2分钟

vuex

【从vuex工作流程的角度】

  • 当vue项目需要进行跨组件共享数据或缓存数据时,我们会用到vuex。

  • 安装vuex,在src/store中编写状态管理的逻辑。

  • src/store/index.js注册vuex、创建store(要分modules),抛出store。

  • 在main.js中挂载store。

  • 我们把需要共享的数据定义在子store,并且开启命名空间。

    • 用state定义共享数据。
    • 用mutations定义修改state的方法,用actions封装调接口的方法。
  • 在src/store/index.js使用modules字段合并子store。

  • 在vue组件中使用state,mutations,actions:

    • 在vue组件中使用state,要么使用this.$store.state来访问(不建议),要么使用mapState()访问(建议)。
    • 映射进入组建后,就可以使用this来访问它们了(getters和state的用法是一样的)。
    • 在vue组件中使用mutations,要么用this.$store.commit('mutations方法',‘数据’)提交并触发,要么使用mapMutations映射进来,使用this来访问它们。
    • 在vue组件中使用actions,要么用this.$store.commit('actions方法',‘数据’)提交并触发,要么使用mapMutations映射进来,使用this来访问它们。

总结:把需要共享或缓存的后端数据定义在state中,(数据在后端,怎么拿到数据?)封装api在actions定义方法(这个方法给谁用?)在vue组件触发actions方法,actions方法调接口,拿到后端数据,在actions方法内部使用mutations方法来修改state,因为state是响应式的,所以当state放生变化vue组件视图会自动更新。这就是vuex基本工作流程,也是所谓Flux单向数据流的基本思想。

【从数据流的角度】

思考:数据库中的数据 -> ..... ->视图渲染 的过程。

  • 数据放在数据库,我们要封装axios调接口。
  • 后端数据回来时,axios拦截器首先拿到。
  • 一般调接口,一般在vuex的actions调接口,拿到数据交给mutations。
  • mutations拿到数据,交给sate。
  • state数据给页面使用,一把在组件的计算属性中拿到数据。
  • 组件拿到stae数据,给指令使用来渲染页面。

【注意】

  • 不建议直接修改this.$store.state.count,因为不走流程devtool监听不到。

  • 不建议在mutations使用异步逻辑,比如定时器或调接口。mutations方法用于同步更新state。

    • 为什么不建议使用异步逻辑呢?原因是devtools识别不了。
  • actions作用:vuex官方建议的一种用于与后端通信的方式

    • 使用:在actions方法用于调接口,在组件中this,$store.dispatch('xxxFetchApi','数据')。
  • 注意:我们只是建议actions方法用于调接口,事实上在actions方法也可以直接修改state。

  • getter

    • 作用:相当于是vue的computed计算属性,常常用于对state变量进行二次计算。
  • 最佳实践需要用modules模块化(注意在子store使用命名空间namespaced)。

代码

目录结构

src
├── views
│   ├── example.vue
├── main.js
├── store
│   ├── index.js
│   └── modules
│       ├── study.js
/src/main.js
// 入口文件
import Vue from 'vue'
// 根组件
import App from './App.vue'// 如果项目上线,关闭掉vue的报错等提示
Vue.config.productionTip = falseimport router from '@/router'
import store from '@/store'import api from '@/api'
Vue.prototype.$api = api
​
new Vue({
  render: h => h(App),
  el: '#app',
  router,  // 挂载路由系统
  store
})
​
/src/views/example.vue
<template>
<div class="vuex-example">
  <h3>vuex-example</h3>
  <h3 v-text='count'></h3>
  <button @click='change("add")'>自增</button>
  <button @click='change("sub")'>自减</button>
  <hr>
​
  <div v-for='item in list' :key='item.n' v-text='item.k'></div>
</div>
</template><script>
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
  data() {
    return {}
  },
  computed: {
    ...mapState('study', ['list', 'count'])
  },
  created() {
    this.getList({ct:10})
  },
  methods: {
    ...mapActions('study', ['getList']),
    ...mapMutations('study', ['changeCount']),
  }
}
</script>
/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
​
import study from './modules/study'// 怎么理解store(状态管理)?
// 你可以把store理解成当前应用程序的“数据仓库”“数据银行”
export default new Vuex.Store({
  // modules
  // 作用:从vue项目管理的角度来思考,当多人协同开发时,我们希望把这个根store拆分成多个子store。好处是多人开发时彼此不干扰,其次便于代码的维护。
  modules: {
    study
  }
})
​
/src/store/modules/study.js
import { fetchQqList } from '@/api'// state
const state = {
  count: 1,
  list: []
}
​
// mutations
const mutations= {
  changeCount(state, payload) {
    if (payload.type==='add') {
      state.count += payload.step
    } else {
      state.count -= payload.step
    }
  },
  updateList(state, payload) {
    state.list = payload
  }
}
​
// actions
const actions = {
  getList (store, payload) {
    fetchQqList(payload).then(res=>{
      console.log('vuex 音乐接口', res)
      store.commit('updateList', res.hotkey)
    })
  }
}
​
// getters
const getters = {
  musicLeng(state) {
    return state.list.length
  }
}
​
export default {
  // 开启子store命名空间,彻底地把多个子store独立开来。
  namespaced: true,
  state,
  getters,
  mutations,
  actions
}

一些思想

要站在流程的角度去思考代码,不要只看代码本身。