- Vuex 使用的是单一状态树,使用一个对象就包含了全部的应用层级状态
- 可以在store中设置模块
- 改变状态必须通过
mutation
创建store文件,创建store和mutations
import {createStore} from 'vuex'
const store = createStore({
state: ()=>({
counter: 0
}),
mutations:{
increment(state){
state.counter++
}
}
})
export default store
注册store
import './assets/main.css'
import { createApp } from 'vue'
import store from './store'
import App from './App.vue'
const app = createApp(App)
app.use(store)
app.mount('#app')
组件中使用store,必须提交mutation
<template>
<div class="app">
<h1>{{ $store.state.counter }}</h1>
<button @click="increment">增加计数</button>
</div>
</template>
<script setup>
import {useStore} from 'vuex'
const store = useStore()
function increment(){
store.commit('increment')
}
</script>
- 使用
mapState
在options
中使用非常方便
<template>
<div class="app">
<h1>{{ counter }}</h1>
<h1>{{ newCounter }}</h1>
<button @click="increament">改变计数</button>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default{
computed:{
...mapState(['counter']),
...mapState({
newCounter: state=> state.counter
})
},
methods:{
increament(){
this.$store.state.counter++
}
}
}
</script>
在setup中mapState
并不好用,因为setup中是this
指向上下文的,所以需要手动修改函数的this
指向
<template>
<div class="app">
<h1>{{ counter }}</h1>
</div>
</template>
<script setup>
import { computed } from 'vue'
import {mapState, useStore} from 'vuex'
const {counterFn} = mapState(['counter'])
const store = useStore()
const counter = computed(counterFn.bind({$store:store}))
</script>
- 在
setup
中解构store,包装响应式
<template>
<div class="app">
<h1>{{ counter }}</h1>
</div>
</template>
<script setup>
import {toRefs} from 'vue'
import {useStore} from 'vuex'
const store = useStore
const {counter} = toRefs(store.state)
- 用于状态计算
import {createStore} from 'vuex'
const store = createStore({
state: ()=>({
counter: 1,
user:[
{age:18},
{age:15},
{age:14},
]
}),
getters:{
totalAges(state){
return state.user.reduce((prev, ele)=>{
return prev + ele.age
}, 0)
}
},
})
export default store
组件直接使用
<template>
<div class="app">
<h1>{{ $store.getters.totalAges }}</h1>
</div>
</template>
- 在getters中使用其他getters函数
getters
提供了第二个默认参数来获取getters对象
getters:{
totalAges(state){
return state.user.reduce((prev, ele)=>{
return prev + ele.age
}, 0)
},
message(state, getters){
return `totalAges is ${getters.totalAges}`
}
},
然后在组件中直接使用
<template>
<div class="app">
<h1>{{ $store.getters.totalAges }}</h1>
<h1>{{ $store.getters.message }}</h1>
</div>
</template>
- getters返回函数,根据组件传参,实现动态获取值
const store = createStore({
state: ()=>({
users:[
{id:'1',age:18},
{id:'2',age:15},
{id:'3',age:14},
]
}),
getters:{
getUserInfo(state, getters){
return function(id){
return state.users.find(user => user.id === id)
}
}
},
})
组件中直接使用
<template>
<div class="app">
<h1>{{ $store.getters.getUserInfo('1') }}</h1>
</div>
</template>
<template>
<div class="app">
<h1>{{ totalAges }}</h1>
<h1>{{ message }}</h1>
<h1>{{ getUserInfo('1') }}</h1>
<button @click="increament">改变计数</button>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default{
computed:{
...mapGetters(['totalAges','message','getUserInfo'])
},
}
</script>
第一种方式:
<script setup>
import { computed } from 'vue'
import {mapGetters, useStore} from 'vuex'
const store = useStore()
const {totalAges:totalAgesFn} = mapGetters(['totalAges'])
const totalAges = computed(totalAgesFn.bind({$store:store}))
const {message:messageFn} = mapGetters(['message'])
const message = computed(messageFn.bind({$store:store}))
const {getUserInfo:getUserInfoFn} = mapGetters(['getUserInfo'])
const getUserInfo = computed(getUserInfoFn.bind({$store:store}))
</script>
第二种方式:
<script setup>
import { toRefs } from 'vue'
import {useStore} from 'vuex'
const store = useStore()
const {totalAges,message,getUserInfo} = toRefs(store.getters)
</script>
第三种方式:
<script setup>
import { computed,toRefs } from 'vue'
import {useStore} from 'vuex'
const store = useStore()
const totalAges = computed(()=>store.getters.totalAges)
const message = computed(()=>store.getters.message)
const getUserInfo = computed(()=>store.getters.getUserInfo)
</script>
vuex中不应该手动更改状态,而必须通过提交mutation
定义mutations
const store = createStore({
state: ()=>({
counter: 1,
}),
mutations:{
increment(state){
state.counter++
},
},
})
<script>
export default{
methods:{
increment(state){
this.$store.commit('increment')
}
}
}
</script>
<script setup>
import { useStore } from 'vuex';
const store = new useStore()
function increment(){
store.commit('increment')
}
</script>
<script>
import { mapMutations } from 'vuex';
export default{
methods:{
...mapMutations(['increment'])
}
}
</script>
需要进行手动绑定,改变this
<template>
<div class="app">
<h1>{{ store.state.counter }}</h1>
<button @click="increment">改变计数</button>
</div>
</template>
<script setup>
import { useStore,mapMutations } from 'vuex';
const store = new useStore()
const mutations = mapMutations(["increment"])
const newMutations = {}
Object.keys(mutations).forEach(key => {
newMutations[key] = mutations[key].bind({ $store: store })
})
const { increment} = newMutations
</script>
-
如果有异步操作需要在vuex中执行,应该讲异步操作放入
actions
;mutations中只能放入同步操作 -
actions
需要通过commit
提交mutation
,进而改变状态;mutaions中可以直接修改状态;
在组件中使用时,对于mutation
可以直接commit
,但对于actions
是dispatch
提交action
操作
const store = createStore({
state: ()=>({
counter: 1,
}),
mutations:{
increment(state){
state.counter++
},
},
actions:{
incrementAction(context){
context.commit('increment')
},
},
})
组件中使用
<script>
export default {
methods:{
increment(){
this.$store.dispatch('incrementAction')
}
}
}
</script>
<script setup>
import { useStore } from 'vuex';
const store = new useStore()
function incrementAction(){
store.dispatch('incrementAction')
}
function updateInfoAction(payload){
store.dispatch('updateInfoAction',payload)
}
</script>
mutations:{
increment(state){
state.counter++
},
updateInfo(state,payload){
state.info.age = payload
}
},
actions:{
incrementAction(context){
context.commit('increment')
},
updateInfoAction(context, payload){
context.commit('updateInfo',payload)
}
},
组件中使用
<template>
<div class="app">
<h1>{{ $store.state.counter }}</h1>
<button @click="incrementAction">改变计数</button>
<h1>{{ $store.state.info.age }}</h1>
<button @click="updateInfoAction(27)">改变数据</button>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
methods:{
...mapActions(['incrementAction', 'updateInfoAction'])
}
}
</script>
<script setup>
import { useStore, mapActions } from 'vuex';
const store = new useStore()
const actions= mapActions(['incrementAction','updateInfoAction'])
const newActions = {}
Object.keys(actions).forEach((actionName)=>{
newActions[actionName] = actions[actionName].bind({$store:store})
})
const {incrementAction,updateInfoAction } = newActions
</script>
作用:给store
划分模块,将相关的state
,mutations
,actions
放到同一个模块中
抽离出user
到一个单独的store/modules/user.js
文件中:
export default {
state:()=>({
info:{
age:20
}
}),
mutations:{
updateInfo(state,payload){
state.info.age = payload
}
},
actions:{
updateInfoAction(context, payload){
context.commit('updateInfo',payload)
}
},
}
在store文件中引入:
import {createStore} from 'vuex'
import userState from './modules/user'
const store = createStore({
state: ()=>({
counter: 1,
}),
modules:{
user:userState,
}
})
export default store
在组件中使用时,要在对象获取时加一层模块:
<template>
<div class="app">
<h1>{{ $store.state.user.info.age }}</h1>
</div>
</template>