Vuex的基础使用

Vuex简介

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。

安装

npm install vuex

使用

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
    state: {
    	count: 0
    },
    mutations: {
        increment (state) {
        	state.count++
        }
    }
})

//main.js
const app = new Vue({
	el: '#app',
    // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
    store,
})

五大核心概念

state

用来存放共享数据的

const store = new Vuex.Store({
    state: {
        count: 10,
        like:["篮球","足球"],
        movie:{"name":"速度与激情",actor:"保罗沃克"}
    }
})

组件中使用

需要在computed写(让数据具有响应式)

使用数据:this.$store.state.like(获取like数组)

getters

类似于计算属性 ,默认接受第一个参数,该参数是所有的state,其他的用法跟computed是一模一样的

第二个参数是所有的getters

1.基本用法

index.js

const store = new Vuex.Store({
    state: {
    	count: 10
    },
    getters:{
        money(state){
        	return state.count+"元"
        }
    }
})

组件中

mounted(){
console.log(this.$store.getters.money) //10元
},
2.传参

返回函数,使用该函数时可以传参数

getters:{
    meiyuan:state=>(rate)=>{
    return state.rmb/rate
    }
},
3.第二个参数

第二个参数存放所有getters,打点可以调用

getters:{
    money(state,getters){
    	return getters.info+"元"
    },
    info(state){
    	return state.count*2
    }
}

mutations

1.基本用法

1.修改state数据的唯一办法就是提交mutation

2.mutations中修改的数据如果是引用类型,一定注意要完整的赋值(不能单独修改某一项)

mutation要通过commit提交

调用const store = new Vuex.Store({
    state: {
    	count: 1
    },
    mutations: {
        increment (state) {
            // 变更状态
            state.count++
        }
    }
})
export default store

//调用
 this.$store.commit('increment')
2.载荷(payload)

可以向 store.commit 传入额外的参数,即 mutation 的载荷(payload):

mutations: {
	increment (state, n) {
		state.count += n
	}
}

//调用		
store.commit('increment', 10)

大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读

mutations: {
    increment (state, payload) {
    	state.count += payload.amount
    }
}

//调用
store.comit(“increment”,{amount:10})
3.对象风格的提交方式

type是store的mutations对应名字方法,固定的

mutations: {
    increment (state, payload) { //此时payload是包含着type的
    	state.count += payload.amount
    }
}

//调用
store.commit({
    type: 'increment',
    amount: 10
})
4.Mutation 必须是同步函数

为何mutation不能包含异步操作?

使用层面:代码更高效易维护, 逻辑清晰(规范,而不是逻辑的不允许);

具体原因:为了让devtools 工具能够追踪数据变化;

具体原因详解

每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来(每次状

态的改变都会生产一个全新的 state 对象),然后就可以实现 “time-travel” 了。如果mutation支持异

步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。

注: vue-devtools 的时间旅行 - time travel

Vuex 借鉴 Flux 单向数据流思想,采用集中式统一管理保存状态。但是这些状态不会随时间改变而变

化。为了使状态,可以被捕获、重播或重现。vue-devtools工具,可以帮助我们的 Vue 应用可以实现这

种时间旅行!

每次状态的改变都会生产一个全新的 state 对象,当你想展现什么时间段的状态,只需要切换到那个时

间段的 state 对象,所以vuex原则上只能通过mutation 并且非异步更改状态,否则无法实现state修改

的记录保留或无法正确记录。

actions

1.使用

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。

  • Action 可以包含任意异步操作。

  • 传入的是context(不是state,store对象)

例子:

const store = new Vuex.Store({
    state: {
    	count: 0
    },
    mutations: {
        increment (state) {
        	state.count++
        }
    },
    actions: {
        increment (context) {
        	context.commit('increment')
        }
    }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,这个属性中包括如下:

context:{

state, 等同于store.$state,若在模块中则为局部状态

rootState, 等同于store.$state,只存在模块中

commit, 等同于store.$commit

dispatch, 等同于store.$dispatch

getters 等同于store.$getters

}

常规写法调用的时候会使用context.commit,但更多的是使用es6的变量解构赋值,也就是直接在参数的位置写自己想要的属性,如:{commit}。

2.组件中调用

分发action(dispatch):

store.dispatch('increment')

//带参数的形式
// 以载荷形式分发
store.dispatch('incrementAsync', {
	amount: 10
})

// 以对象形式分发
store.dispatch({
    type: 'incrementAsync',
    amount: 10
})

modules

1.基本用法

Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter

单独定义一个模块跟我们之前定义store是一样的,导出对象就可以了

moduleA.js

export default{
    state:{
    	text:"我是moduleA的数据"
    },
    getters:{},
    mutations:{},
    actions:{}
}

moduleB.js

export default{
    state:{
    	text:"我是moduleB的数据"
    },
    getters:{},
    mutations:{},
    actions:{}
}

store-index.js

import Vue from "vue";
import Vuex from "vuex";
import moduleA from "./moduleA"
import moduleB from "./moduleB"

Vue.use(Vuex);

const store=new Vuex.Store({
    state:{
    },
    modules:{
        // 模块名:模块对象
        moduleA,moduleB
    }
})

export default store

读取数据语法:

this.$store.state.模块名.数据名
//例如
this.$store.state.moduleB.text
2.多层嵌套

每一个子模块依旧可以有自己的子模块,比如moduleA里添加一个moduleC

moduleC.js

export default{
    state:{
    	text:"我是moduleC的数据"
    },
    getters:{},
    mutations:{},
    actions:{}
}

moduleA.js

import moduleC from "./moduleC"
export default{
    state:{
        text:"我是moduleA的数据"
    },
    getters:{},
    mutations:{},
    actions:{},
    modules:{
        moduleC
    }
}

访问:

this.$store.state.模块名.子模块名.数据名
//例如
this.$store.state.moduleA.moduleC.text
3.命名空间

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的,所以直接提交mutation不需要加模块名字,A和B的mutation都能触发

getters也是同理,多个模块都有同一个getter(一样的名字,不建议,一般也不允许这样写),默认读取的是根store的getters(只能用一个),如果根store中没有,则按照模块注册顺序读取

例子

moduleA.js

export default{
    state:{
    	text:"我是moduleA的数据"
    },
    mutations:{
        changeText(state){
        	state.text="moduleA的数据改了"
    	}
    }
}

moduleB.js

export default{
    state:{
    	text:"我是moduleB的数据"
    },
    mutations:{
        changeText(state){
        	state.text="moduleB的数据改了"
        }
    }
}

MyHome.vue

computed:{
    textA(){
        console.log(this.$store.state)
        return this.$store.state.moduleA.text
    },
    textB(){
        console.log(this.$store.state)
        return this.$store.state.moduleB.text
    }
},
methods:{
    //我们会发现我们直接提交mutation不需要加模块名字,A和B的mutation都能触发
    changeText(){
    	this.$store.commit("changeText")
    }
}

开启命名空间

可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。

当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名

例子

moduleA.js

import moduleC from "./moduleC"

export default{
    namespaced: true, //开启命名空间
    state:{
    	text:"我是moduleA的数据"
    },
    getters:{
        info(){
        	return "哈哈"
        }
    },
    mutations:{
    	changeText(state){
    	state.text="moduleA的数据改了"
    	}
    },
    modules:{
    	moduleC
    }
}

此时修改数据需要加上模块名

this.$store.commit("moduleA/changeText")//代表提交moduleA里的changeText
//对于嵌套模块
this.$store.commit("moduleA/moduleC/changeText")//提交moduleA里的moduleC里的
changeText
//对于getters
this.$store.getters["moduleA/info"]
//对于actions
this.$store.dispatch("moduleA/actionA")
4.访问全局内容

在开启了命名空间的模块内部,也是可以访问到全局数据的

getters中可以拿到全局的state和getters

rootState拿到所有模块的数据,rootGetters拿到所有模块的

someGetter (state, getters, rootState, rootGetters) {
    getters.someOtherGetter // -> 'foo/someOtherGetter'
    rootGetters.someOtherGetter // -> 'someOtherGetter'
},

actions中可以拿到所有的state和getters

context可以拿到所有模块的

actions:{
    actionA(context){
    	console.log(context)
    }
},

在模块内部提交全局(根store)的action或者mutation

将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。

dispatch('someOtherAction') // -> 'foo/someOtherAction'
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
commit('someMutation') // -> 'foo/someMutation'
commit('someMutation', null, { root: true }) // -> 'someMutation'

辅助函数

mapState函数返回值是一个对象

其他的:mapGetters;mapMutations;mapActions

使用辅助函数之后,组件可以直接在模板用(方法也是),不用再写this.store这种引入

使用:

import { mapState } from 'vuex'
//使用扩展运算符将辅助函数和其他计算属性混合到一起,组成一个对象
//mapState
computed:{
    ...mapState(["money","a","b","c"]),
    sex(){
    }
},

带命名空间的辅助函数

...mapMutations("moduleA",["changeText"])
...mapState("moduleA/moduleC",["text"]),

还可以通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数(一般不用)。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:

import { createNamespacedHelpers } from 'vuex'
const { mapState } = createNamespacedHelpers('moduleA/moduleC')
computed:{
	...mapState(["text"]),//这样text默认就是在moduleA/moduleC下的
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值