Vuex 适用于复杂的状态管理
Vue3里面安装指定版本
npm install vuex@next
Vuex的基本使用过程
简单版本
- 创建与components同级的文件夹store / index.js
import {createStore} from 'vuex'
const store = createStore({
state(){
return{
count:0
}
},
mutations:{
increment(state){
state.count++
},
decrement(state){
state.count--
}
},
})
export default store
- main.js 入口文件引入store
import {createApp} from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')
- Home.vue
<template>
<h2>{{$store.state.counter}}</h2>
<button @click='increment'>+1</button>
<button @click='decrement'>-1</button>
</template>
<script>
import {mapMutatons} from "vuex"
export default{
setup(){
const storeMutations = mapMutations(['increment','decrement'])
return {
...storeMutations
}
}
}
</script>
组件获取状态state
mapState 辅助函数
Home.vue
<template>
<h2> Home(computed):{{sCounter}}</h2>
<h2>{{counter}}</h2>
<h2> {{height}} </h2>
</template>
Options API 实现
<script>
import {mapState} from 'vuex'
1 or 2 or 3 or 4
</script>
- 通过组件内计算属性取别名
computed:{
sCounter(){
return this.$store.state.counter
}
}
- 通过mapState函数将所有vuex里的state属性拿到组件映射计算属性
computed:mapState()
- mapState数组写法,保留组件自身计算属性➕其他vuex里的属性
通过计算属性映射过来的属性,template里用的时候可以直接用{{counter}} 而不必加$store.state
computed:{
homeKey(){
return 'home private key'
},
...mapState(["counter","age","height"])
}
- mapState对象写法,可以给state里面的属性在组件内取别名(函数返回值的形式)
computed:{
...mapState({
sCounter:state => state.counter
})
}
Componsition API 实现
<script>
import {computed} from 'vue'
import {mapState,useStore} from 'vuex'
// mapState返回值是一个对象,对象里面是一个一个的函数,函数调用后得到的是state里对应的属性值
export default{
setup(){
const store = useStore()
//1.直接用computed 映射
const sCounter = computed(()=>store.state.counter)
//2 mapState传入数组
const storeStateFns = mapState(["counter","height","age"])
const storeState = {}
// 遍历
Object.keys(stroeStateFns).forEach(fnKey=>{
// 因为setup中没有this,此时必须传入{$store:state},将vuex的state手动指给调用函数
const fn = storeStateFns[fnKey].bind({$store:state})
storeState[fnKey] = computed(fn) // 转变为计算属性
})
return {
sCounter,
...storeState
}
}
}
</script>
将遍历state属性这段抽离成hooks / useState.js
import {computed} from 'vue'
import {mapState,useStore} from 'vuex'
export function useState(mapper){
const store = useStore()
const storeStateFn = mapState(mapper)
const storeState = {}
Object.keys(storeStateFn).forEach(fnKey => {
const fn = storeStateFn[fnKey].bind({$store:State})
storeState[fnKey] = computed(fn)
})
return storeState
}
组件中使用useState.js函数
<script>
import useState from '../hooks/useState'
export default{
setup(){
const storeState = useState(["counter","age","height"])
return {...storeState}
}
}
</script>
getters的基本使用
组件内不直接使用vuex的属性,需要变化一下的时候使用getters
store / index.js
import {createStore} from 'vuex'
const store = createStore({
state(){
return{
counter:0,
books:[
{
name:"计算机组成原理",
count:50,
price:22
},
{
name:"单片机开发实践",
count:20,
price:18
},
]
}
},
mutations:{
increment(state){
state.counter++
},
decrement(state){
state.counter--
}
},
getters:{
//求和
totalPrice(state,getters){
return state.books.reduce((pre,cur)=>{
return pre+cur.count*cur.price
},0)
},
nameInfo(state){
return `name:${state.name}`
}
}
})
mapGetters辅助函数
组件内使用
<h2>总价值{{totalPrice}}</h2>
<script>
import {mapGetters} from 'vuex'
export default{
computed:{
nameInfo(){ return this.$store.getters.nameInfo},
computed:{...mapGetters},
computed:{
...mapGetters(["nameInfo","ageInfo","heightInfo"])
},
computed:{
...mapGetters({
sNameInfo:"nameInfo"
})
}
}
}
</script>
Componsition API使用
import {computed} from 'vue'
import {mapGetters,useStore} from 'vuex'
export default{
setup(){
const store = useStore()
const sNameInfo = computed(()=>store.getters.nameInfo)
const storeGettersFns = mapGetters(["nameInfo","ageInfo"])
const sotreGettrs = {}
Object.keys(storeGettersFns).forEach(fnKey = >{
const fn = storeGettersFns[fnKey].bind({$store:store})
storeGetters[fnKey] = computed(fn)
})
return{
sNameInfo,
...sotreGettrs
}
}
}
与useState很像,除了mapState 和 mapGetters不同,所以再抽出公用部分
hooks/index.js
import {useState} from './useState'
import {useGetters} from './useGetters'
export {useState,useGetters}
hooks/useMapper.js
import {computed} from 'vue'
import {useStore} from 'vuex'
export function useMappr(mapper,mapFn){
const store = useStore()
const storeStateFn = mapFn(mapper)
const storeState = {}
Object.keys(storeStateFn).forEach(fnKey => {
const fn = sotreStateFn[fnKey].bind({$store:store})
storeState[fnKey] = computed(fn)
})
return storeState
}
hooks/useGetters.js
import {mapGetter} from 'vuex'
import {useMapper} from './useMapper'
export function useGetters (moduleName,mapper){
let mapperFn = mapGetters
return useMapper(mapper,mapperFn)
}
hooks/useState.js
import {mapState} from 'vuex'
import {useMapper} from './useMapper'
export function useState (moduleName,mapper){
let mapperFn = mapState
return useMapper(mapper,mapperFn)
}
组件内使用
import {useGetters,useState} from '../hooks/index'
setup(){
const storeGetters = useGetters(["nameInfo","ageInfo","heightInfo"])
const storeState = useState(["counter","name","age","height"])
return {
...storeGetters,
...storeState
}
}
Mutations基本使用
更改Vuex的store中的状态的唯一方法是提交mutations
Options API 使用
1.
this.$store.commit("mutations里方法名",{传递的参数对象})
2
this.$store.commit({
type:"mutations里方法名",
age:12,
...传递参数
})
一般多个地方要用到同一个变量名字的时候,可以将其封装为常量文件
store / mutations-type.js
export const INCREMENT_N = "increment_n"
store / index.js
import {INCREMENT_N} from "./mutations-type'
mutations:{
[INCREMENT_N](state,payload){
state.counter += payload.n
}
}
mapMutations辅助函数
组件内使用
mapMutations返回的是一个对象,对象里面是一个函数,方法绑定也是函数,不必再转换了
<button @click='increment_n({n:10)'>+10</button>
<script>
import {mapMutations} from 'vuex'
import {INCREMENT_N} from '../store/mutations-type'
export default{
setup(){
const storeMutations = mapMutations(['increment','decrement',INCREMENT_N])
return {
...storeMutations
}
}
}
</script>
Actions
异步操作都放在这里,比如网络请求
actions 与 mutations的区别:
- actions 提交的是mutations,而不是直接更改state里面的状态
- actions 可以包含任意异步操作
actions使用
组件内
methods:{
this.$store.dispatch("actions里面的名字",{传递的参数,可以不传})
}
store / index.js
import {createStore} from 'vuex'
const store = createStore({
state(){
return{
banners:[]
}
},
mutations:{
increment(state,payload){
state.counter++
}
},
actions:{
incrementAction(context,payload){
//异步操作
setTimeout(()=>{
context.commit("increment")
},1000)
}
}
})
- context 里面都有什么?
name | 含义 | 用法 |
---|---|---|
commit | 调用mutations里的方法 | commit("") 等同于 context.commit() |
dispatch | 调用actions里面的其他方法 | dispatch() |
getters | 获取getters里面某一个属性 | getters() 等同于 context.getters() |
state | 获取state里面的值 |
- context 解构
actions:{
decrementAction({commit,dispatch,state}){
commit("decrement")
}
}
组件中使用actions里面方法的另一种写法
methods:{
decrement(){
this.$store.dispatch({
type:"decrementAction"
})
}
}
mapActions辅助函数
组件中使用
<script>
import {mapActions} from 'vuex'
export default{
methods:{
...mapActions(["decrementAction","incrementAction"]),
...mapActions({
add:"incrementAction",
sub:"decrementAction"
})
},
setup(){
const actions = mapActions(["decrementAction","incrementAction"])
return{
...actions
}
}
}
</script>