vuex 4 安装
几乎所有的 Vuex 4 API 都与 Vuex 3 保持不变。但是,仍有一些非兼容性变更需要注意
yarn add vuex@next -- save
src 目录下新建 store/index.js
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
state () {
return {
count: 0
}
},
mutations: {
increment (state) {
state.count++
}
}
})
export default store
在main.js中引入store,并引用
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App)
.use(router)
.use(store)
.mount('#app')
现在,可以通过 store.state 来获取状态对象,并通过 store.commit 方法触发状态变更:
store.commit('increment')
console.log(store.state.count) // -> 1
组合式API
在 Vue 组件中, 传统写法是通过 this.$store 访问store实例
在vue3中则是通过调用 useStore 函数,这与在组件中使用选项式API访问 this.$store 是等效的
<template>
<!-- 传统写法 -->
<p @click="$store.commit('increment')">{{ $store.state.count }}</p>
<!-- composition写法 -->
<p @click="increment()">{{ state.count }}</p>
</template>
<script setup>
import { useStore } from "vuex"
const store = useStore()
const state = store.state
function increment() {
store.commit('increment')
}
</script>
访问 State 和 Getter
访问 state 和 getter,需要创建 computed 引用已保留响应性,这与在选项式API中创建计算属性等效
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'
const store = useStore()
// 在computed函数中访问state
const count = computed(() => store.state.count)
// 在computed函数中访问getter
const double = computed(() => store.getters.double)
// 通过 ...toRefs解构state为响应式
const { count } = {...toRefs(store.state)}
</script>
访问 Mutation 和 Action
要使用 mutation 和 action 时,只需要调动 commit 和 dispatch 函数
<script setup>
import { useStore } from 'vuex'
const store = useStore()
// 使用mutation
const increment = (x, y) => store.commit('increment', {x, y})
// 使用action
const asyncIncrement = x => store.dispatch('asyncIncrement', x)
</script>
严格模式
开启严格模式
仅需在创建 store 的时候传入 strict: true:
const store = createStore({
// ...
strict: true
})
在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
不要在发布环境下启用严格模式!
严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失。
类似于插件,我们可以让构建工具来处理这种情况:
const store = createStore({
// ...
strict: process.env.NODE_ENV !== 'production'
})
表单处理
在严格模式中,v-model 修改 state 会比较棘手
<input v-model="obj.message">
如果obj.message 是一个字计算属性中返回的一个 Vuex store 对象,在用户输入时,v-model 会试图直接修改 obj.message,在严格模式中,由于状态修改不是通过mutation提交的,严格模式下就会抛出错误
改为事件触发提交
用vuex的思维去解决这个问题的方法,便是不采用v-model方式,而是给 绑定 value,然后侦听 input 或者 change 事件,在事件中向mutation提交
<template>
<input :value="message" @input="updateMessage">
</template>
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'
const store = useStore()
const message = computed(() => store.state.message)
const updateMessage = e => store.commit('updateMessage', e.target.value)
</script>
下面是mutation函数
// ...
mutations: {
updateMessage (state, message) {
state.obj.message = message
}
}
双向绑定的及计算属性
上面的方法比简单地使用“v-model + 局部状态”要啰嗦得多,并且也损失了一些 v-model 中很有用的特性。另一个方法是使用带有 setter 的双向绑定计算属性:
<template>
<input v-model="message">
</template>
<script setup>
import { useStore } from 'vuex'
const store = useStore()
const message = computed({ //xxxxxxx有问题
get() {
return store.state.obj.message
},
set(value) {
store.commit('updateMessage', value)
},
})
</script>