Vue3.0的学习(3)之 VueX

158 阅读1分钟

这章咱们继续学习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.jsmodules文件夹中,其中放着我们这个应用相对应的状态。当然我们现在先放入一些基础状态

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>