【从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 = false
import 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
}
一些思想
要站在流程的角度去思考代码,不要只看代码本身。