文章目录
用处
vuex专门用于解决共享数据问题,是将数据提升到顶层,不过他使用了一些特别的技巧,不仅让组件的依赖更加清晰,当数据变动时,仅渲染依赖该数据的组件
注意:并非所有数据都需要用vuex管理,通常vuex只管理那些需要被组件共享的数据
在实际开发中,一些逻辑特别复杂的数据,尽管不共享,也可能提取到vuex中进行管理
解析
结构
import Vue from 'vue'
import VueX from 'vuex'
Vue.use(VueX)
const store = new VueX.Store({
state:{ // 仓库
count:0
// 访问 this.$store.state.count
},
mutations:{ // 状态更新 只能通过mutations的方法修改 仓库数据
// 修改仓库内容 浏览器场景devtoos 可检测到修改信息
// 不能执行异操作 不然检测的修改记录不准确
// 事件类型:回调函数
// 修改仓库数据
// state 仓库 payload 参数(负荷:携带着某某)
setCount(state, payload){
state.count = payload
}
// 通过mutations 更新
普通提交风格
// this.$store.commit('setCount',2)
// payload => 2
特殊提交风格
// this.$store.commit({
// type:'setCount',
// count:2,
// age:18
// })
// payload => {type:'setCount',count:2,age:18}
},
actions:{ // 执行异步操作的地方
// 操作mutations方法
// 当前store对象 context.commit-> this.$store.commit
operationCount(context, payload){
context.commit('setCount',2)
}
// 调用 operationCount
// this.$store.dispatch('operationCount')
},
getters:{ // 类似于计算属性
// 访问 this.$store.getters.xxx
// state 仓库 gettes 当前gettes对象 可用来访问其它gettes方法
getFun(state, gettes){
// gettes.xxx
}
// 传递参数 默认是不能传递参数的 可返回一个函数 调用该函数传参数
getParams(state){
return function(par){
return par*state.count
}
}
// 调用 $store.getters.getParams(99)
},
modules:{ // 多个仓库整合 仓库模块划分
}
})
export default store
单一状态树 state
Vuex提出使用单一状态树
Single Source of Truth => 单一数据源
即全局只使用一个 store 对象
getters使用
仓库
const store = new VueX.Store({
state:{
count:2
},
getters:{
powCount(state){
return state.count*state.count
},
isPow(state, gettes){
return gettes.powCount > 10
},
// 给 getter 传参 返回一个函数 调用该函数传参数
getParams(state){
return function(par){
return par*state.count
}
}
// 简化
getParams: state => par => par*state.count
}
})
组件使用
<template>
<div>
获取count的平方:{{computedCount}}
获取count的平方:{{$store.getters.powCount}}
count的平方是否大于10:{{$store.getters.is20}}
指定一个数乘以count {{$store.getters.getParams(99)}}
</div>
</template>
<script>
export default{
computed:{
computedCount(){ // 直接获取然后计算
return this.$store.state.count * this.$store.state.count
}
}
}
</script>
mutations
mutations 提交风格
普通提交风格
// 触发
this.$store.commit('setCount',2)
// 参数接收
mutations:{
setCount(state, payload){
// payload => 2
}
}
特殊提交风格
// 触发
this.$store.commit({
type:'setCount',
count:2,
age:18
})
// 参数接收
mutations:{
setCount(state, payload){
// payload => {type:'setCount',count:2,age:18}
}
}
mutations 响应规则
Vuex中的store的state是响应式的,当state中的数据发生变化时,Vue组件会自动更新
这必须遵循一些Vuex对应的规则
- 提前在store中初始化好所需的属性(这些属性都会被加入响应式系统中,当属性发生变化时,会通知所有界面中用到该属性的地方,让界面发生刷新)
- 当给state中的对象添加新属性时,使用
- 使用
Vue.set(obj, 'newProp', 123)
- 用新对象给旧对象赋值
- 使用
- 当给state中的对象删除属性时
- 使用
Vue.delete(obj, 'prop')
- 使用
state:{
obj:{
name:"可响应的属性",
}
},
mutations:{
addNewProp(state){
// 给state中的对象添加新属性
// 直接添加是不可响应的
state.obj['name2'] = '不可响应的属性'
// 添加响应式属性 name3属性是可响应的
Vue.set(state.obj, 'name3', '添加响应式属性')
// 赋值一个新对象
state.obj = {...state.obj, name3:'添加响应式属性'}
// 删除属性 该方式删除不会响应
delete state.obj.name
// 删除响应式属性
Vue.delete(state.obj, 'name')
}
}
mutations 常量类型 名称使用常量
当项目增大时,Vuex管理的状态越来越多,需要更新的状态越来越多,那么意味着Mutations中的方法越来越多
方法过多,使用中需要花费大量的精力去记住这些方法,甚至是多个文件间来回切换,查看方法名称,甚至不是复制的时候,还会写错的情况。
mutations-types.js 保存方法名
export const INCREMENT = 'increment'
// 其它mutations类型
// ...
store.js
import Vue from 'vue'
import Vuex from 'vuex'
import {INCREMENT} from './mutations-types'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
},
mutations:{
[INCREMENT]:function(state, payload){
// ...
}
}
})
使用
import {INCREMENT} from './store/mutations-types'
export default{
methods:{
setFun(){
this.$store.commit(INCREMENT)
}
}
}
mutations 同步函数
通常情况下,Vuex要求muations中的方法必须是同步方法
主要原因是当我们使用devtools时,可以让devtools帮助捕捉mutations的提交信息
如果是异步操作,那么devtools将不能很好的追踪这个操作什么时候完成
如果有异步操作 使用actions的方法 来操作mutations
actions
action 类似于Mutation,但是用来代替Mutation来进行异步操作的
actions:{ // 执行异步操作的地方
// 操作mutations方法
// 当前store对象 context.commit-> this.$store.commit
operationCount(context, payload){
context.commit('setCount',payload)
}
// 不能直接操作state
// context.state.xxx = xxx
// 调用 operationCount
// this.$store.dispatch('operationCount', 2)
},
modules
Vue使用单一状态树,那么也就意味着有很多状态都会交给Vuex来管理
当应用变得非常复杂时,store对象就有可能变得非常臃肿,为了解决这个问题,Vuex允许将store分割成模块,而没个模块都有自己的 state mutations actions getters 等
基本使用
结构
modules:{
a:{
state:{},
mutations:{},
getters:{},
actions:{},
modules:{....}
}
}
const moduleA = {
state:{
name:"moduleA"
},
mutations:{
updataName(state, payload){
console.log('moduleA -- mutations')
}
},
getters:{
// state 对应单前模块的getters
// getters对应单前模块的getters
// 在模块里面有第三个参数 rootState 获取根State
repeatName(state, getters, rootState){
return state.name.repeat(10)
}
},
actions:{
actRname(context, payload){
// context.rootGetters
// context.rootState
console.log(context)
setTimeout(() => {
// 只能提交该模块的mutations方法
context.commit('upName',payload)
}, 3000);
}
}
}
const moduleB = {
state:{},
mutations:{},
getters:{},
}
cons store = new Vuex({
modules:{
moduleA,
moduleB
}
})
// 相当于
//state:{
// moduleA:{...}
//}
// 调用
this.$store.state.moduleA.name
this.$store.commit('updataName')
{{$store.getters.repeatName}}
this.$store.dispatch('actRname')
命名空间 namespaced
const moduleA = {
namespaced: true,
mutations:{
setisLoading(state, payload){
//...
}
}
//...
}
// 调用模块A下面的 mutations 的 setisLoading方法
this.$store.commit('moduleA/setisLoading',true)
vuex使用
安装
npm i vuex
main.js配置
import vuex from 'vuex'
Vue.use(vuex )
const store = new vuex.Store({
// 配置
// state:{} //仓库
})
new Vue({
render:h=>h(App)
router,
store
}).$mount("#app")
或者
import {Store} from 'vuex'
new Store({})
分离模块文件配置
新建 store/index.js
import Vue from 'vue'
import vuex from 'vuex'
import user from './user' // 导入用户信息仓库
Vue.use(vuex)
const store = new vuex.Store({
// 配置
modules:{
// user(仓库名称):user
user, // 简写
// ... 其他仓库
}
})
export default store
新建 store/user.js
// 用户信息仓库
export default {
state:{
user:{
data:{}, // 用户信息
isLogin:false // 登录状态
}
}
}
main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store,
}).$mount('#app')
仓库结构
20200721205143871.png)
访问仓库数据
直接访问
this.$store.state.user.isLogin
通过计算属性
computed:{
isLogin(){
return this.$store.state.user.isLogin
}
}
vuex辅助函数
import {mapState} from 'vuex'
computed:mapState('user',['data','isLogin'])
this.isLogin // false
访问多个 访问会以前面的为准
computed:{
...mapState('user',['data','isLogin']),
...mapState('user2',{
user2data:'data',
user2isLogin:'isLogin'
}),
}
修改仓库数据 mutation
数据的改动必须要提交commit
一个mutation
在vuex中,提交mutation是数据变化的唯一原因
在 mutation 中不能出现副作用(不能改动或使用外部的数据,ajax,其他异步行为…)会影响vue监听工具的使用
mutations:{
setData(state,data){
/// setTimeout
}
}
配置
// user
export default {
namespaced:true, // 开启命名空间
state:{
data:[],
isLoading:false
},
mutations:{
// 这里配置多种变异方式
// state:原来的状态
// payload:负荷
setisLoading(state,payload){
state.isLoading = payload
},
setData(state,data){
state.data = data
}
}
}
调用
// 开启命名空间的写法
this.$store.commit('user/setisLoading',true)
// 没有开启命名空间的写法
this.$store.commit('setisLoading',true)
actions 业务逻辑处理
export default {
namespaced:true, // 开启命名空间
state:{
data:[],
isLoading:false
},
mutations:{
setisLoading(state,payload){
state.isLoading = payload
},
setData(state,data){
state.data = data
}
},
actions:{
// context 等同于 this.$store 只能传递一个参数payload
async initData(context,params){
// 由于是在当前命名空间 可不写 channels/
context.commit('setisLoading',true);
let dat = await getNewsChanges() //接口获取数据
context.commit('setData',dat.data);
context.commit('setisLoading',false);
}
}
}
调用 dispatch
触发action
this.$store.dispatch('channels/initData',1)
store 变化逻辑
直接通过mutation 改动仓库数据
通过action 改动仓库数据
在main.js 触发dispatch
// 初始化数据
store.dispatch('user/initData')
store 目录结构
actions.js
export default {
asyncCount(context, payload){
setTimeout(()=>{
context.commit('addCount',payload)
})
}
}
getters.js
export default {
count(state){
return state.count > 10
}
}
mutations.js
export default {
addCount(state, payload){
state.count = payload
}
}
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actionsfrom from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'
const state = {
count:0
}
Vue.use(Vuex)
export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules:{
moduleA
}
})
modules/moduleA.js
export default {
namespaced:true, // 开启命名空间
state:{},
mutations:{},
actions:{},
getters:{}
}