这章咱们继续学习Vue3.0的知识。Vuex是一个高效工具
在Vue3.0中使用 其实与Vue2.0差不多
在cli中如果在安装的时候已经选中了Vuex 将会出现一个store文件夹其中含有index.js (我目前是js为主)
import { createStore } from 'vuex'
export default createStore({
state: {
//单一状态树即单一数据源,在一个项目中只使用一个store对象,来存储所有共享的状态信息
},
getters: {
//类似于计算属性,在数据展示前进行一些变化处理,具有缓存功能,能够提高运行效率
},
mutations: {
//改变state中数据 方法
},
actions: {
//如果确实需要进行一些异步操作,比如网络请求,建议在 Actions 中进行处理,这样 devtools 就能够进行跟踪,由 Actions 处理异步操作,具体的函数部分仍交由 Mutations 进行处理
},
modules: {
//分模块管理数据
}
})
但是呢也可以进行封装各个状态保存相应的区域。分模块来进行管理
我们将在store文件下面新建一个 modules 文件夹 和 getters.js 文件 然后我们修改原来的 index.js
import { createStore } from 'vuex'
import getters from './getters'
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
export default createStore({
modules,
getters
})
modules 存放模块化的相对应的区域 比如我们新建一个 app.js 在 modules文件夹中,其中放着我们这个应用相对应的状态。当然我们现在先放入一些基础状态
const state = { //状态
num:'123'
}
const mutations = { //方法
CHANGE_NUM: (state, num) => {
state.num = num
},
}
const actions = { //一些异步操作
openNum({ commit },num) {
commit('CHANGE_NUM',num)
},
}
export default {
namespaced: true, //你可以在单个模块中通过添加**namespaced:true**的方式使其成为带命名空间的模块。
state,
mutations,
actions
}
我们定义了一个num状态,然后我们定义了一个改变num的方法CHANGE_NUM,我们继续在getters.js 文件下 修改
const getters = {
num: state => state.app.num, //app.js的状态num
}
export default getters
接下来我们在组件中获取这个状态,并改变其状态
<template>
<div class="about">
<h1>{{num}}</h1>
</div>
</template>
<script>
import {computed} from 'vue'
import { useStore} from "vuex";
export default{
setup() {
let store = useStore();
const num = computed({
get: () => store.state.app.num,
set(val) {
console.log(val)
}
})
setTimeout(()=>{
store.dispatch('app/openNum',666)
//store.commit('app/CHANGE_NUM',666)
},3000)
//三秒后数字123变成了666
return{
store,
num
}
}
}
</script>
运行后,num 由原来的123变成666。store中用dispatch方法对应actions,commit方法对应mutations。如果有其他异步的操作可以使用actions进行更改状态,当然目前两者效果一样。
然后就要想一个问题了,之前在Vue2.0中我们使用mapState获取多个状态
computed: {
...mapState({
// ...
})
}
但是在Vue3.0中并不可以。咱们该怎么办呢。查阅过后得到下面的方法。咱们先假设 app.js 中声明
const state = {
num:'123',
allNum:666,
opened:false,
}
const mutations = {
CHANGE_NUM: (state, num) => {
state.num = num
},
}
const actions = {
openNum({ commit },num) {
commit('CHANGE_NUM',num)
},
}
export default {
namespaced: true,
state,
mutations,
actions
}
在 getters.js 中增加声明
const getters = {
num: state => state.app.num,
allNum: state => state.app.allNum,
opened: state => state.app.opened,
}
export default getters
在组件中调用
<template>
<div class="about">
<h1>{{num}}</h1>
<h1>{{allNum}}</h1>
<h1>{{opened}}</h1>
</div>
</template>
<script>
import {computed} from 'vue'
import { useStore,mapState } from "vuex";
export default{
setup() {
let store = useStore();
const storeStateFns = mapState({
num: state => state.app.num,
allNum: state => state.app.allNum,
opened: state => state.app.opened,
})
// storeStateFns = {num:function(){},allNum:function(){},opened:function(){}}
// 对数据进行转化
const storeState = {}
//对sotreStateFns进行Object.keys(sotreStateFns) = [num,allNum,opened]
Object.keys(storeStateFns).forEach(fnKey => {
const fn = storeStateFns[fnKey].bind({$store:store})
storeState[fnKey] = computed(fn)
})
return{
store,
...storeState
}
}
}
</script>
当然这个样子,可以是可以但是代码繁琐。我们可以给他写成一个Hook,多次复用。
import { computed } from 'vue'
import { mapState, useStore } from 'vuex'
export function useState(mapper) {
// 拿到store独享
const store = useStore()
const storeStateFns = mapState(mapper)
// 对数据进行转换
const storeState = {}
Object.keys(storeStateFns).forEach(fnKey => {
const fn = storeStateFns[fnKey].bind({$store: store})
storeState[fnKey] = computed(fn)
})
return storeState
}
在组件中调用
<template>
<div class="about">
<h1>{{num}}</h1>
<h1>{{allNum}}</h1>
<h1>{{opened}}</h1>
</div>
</template>
<script>
import {useState} from '引入刚刚封装的useState.js文件'
export default{
setup() {
const storeState = useState({
num: state => state.app.num,
allNum: state => state.app.allNum,
opened: state => state.app.opened,
})
return {
...storeState
}
}
}
</script>