vue3学习23,24之vuex

104 阅读2分钟

vue devtool

用来调试vuex的数据

devtool安装

在谷歌浏览器中的拓展程序中下载vue devtool

image.png 打开调试在vue中可以进行调试

安装vuex

npm i vuex

vuex基本使用

建立一个store文件夹

import { createStore } from 'vuex'

const store = createStore({
  state() {
    return {
      counter: 100
    }
  },
  mutations: {
    increment(state, payload) {
      state.counter++;
    },
    decrement(state, payload) {
      state.counter--;
    }
  }
});

export default store

在main.js引入

import { createApp } from 'vue'
import App from './App.vue'
import store from './store';

const app = createApp(App);
app.use(store);
app.mount('#app');

在组件中使用,使用方法使用commit

  <div>
    <button @click="increment">+1</button>
    <button @click="decrement">-1</button>
    {{ $store.state.counter }}
  </div>
  methods: {
    increment() {
      this.$store.commit("increment");
    },
    decrement() {
      this.$store.commit("decrement");
    }
  }

mapState

通过mapState方法,可以取出store的state里的属性,将其放在computed中,在template中可以直接引用

<template>
  <div>
    {{ name }}
    {{ age }}
  </div>
</template>

<script>
import { mapState } from 'vuex';

export default {
  computed: {
    ...mapState(['name', 'age'])  
  },
}
</script>

方法里是对象的话可以自定义属性的名称

    ...mapState({
      rename: state => state.name
    })
在setup中使用vuex
  setup() {
    const store = useStore();
    const reage = computed(() => store.state.age)
    return {
      reage
    }
  },

mapState返回的是一个对象中包含许多函数,在optionApi中computed中可以结构,因为computed接收一个个带有返回值的函数,但是setup中不能这么写

  setup() {
    const store = useStore();
    const reage = computed(() => store.state.age)

    const storeStateFns = mapState(['name', 'age', 'counter']);

    const storeState = {};
    Object.keys(storeStateFns).forEach(fnKey => {
      const fn = storeStateFns[fnKey].bind({$store: store})  //绑定this,因为返回值是this.$store.state,如果不绑定会报错
      storeState[fnKey] = computed(fn)
    })
    return {
      reage,
      ...storeState
    }
  },

也可以将封装这个方法封装到一个文件中 src/hooks/useState.js

import { mapState, useStore } from 'vuex';
import { computed } from 'vue';

export function useState(mapper) {
  const store = useStore();
  const storeStateFns = mapState(mapper);
  const storeState = {};
  Object.keys(storeStateFns).forEach(fnKey => {
    const fn = storeStateFns[fnKey].bind({$store: store})  //绑定this,因为返回值是this.$store.state,如果不绑定会报错
    storeState[fnKey] = computed(fn)
  })
  return storeState
}

在.vue文件中使用

  setup() {
    const storeState = useState(['counter', 'name', 'age'])

    return {
      ...storeState
    }
  },

vuex中getters的使用

如果在vuex中某些属性需要变化后使用,可以使用getters,类似于computed

  mutations: {
    increment(state) {
      state.counter++;
    },
    decrement(state) {
      state.counter--;
    }
  },
  getters: {
    recounter(state, getters) {
      return state.counter * 2
    }
  }

使用$store.getters.recounter调用

mapgetters使用

  getters: {
    recounter(state) {
      return state.counter * 2
    }
  }
  //.vue文件
import { mapState, useStore, mapGetters } from 'vuex';
  computed: {
    ...mapGetters(['recounter'])
  },

在setup中使用

  setup() {
    const store = useStore();
    const reCounter = computed(() => store.getters.recounter)

    return {
      reCounter
    }
  },

与mapState类似,可以对mapGetters进行一个封装

import { mapGetters, useStore } from 'vuex';
import { computed } from 'vue';

export function useState(mapper) {
  const store = useStore();
  const storeStateFns = mapGetters(mapper);
  const storeState = {};
  Object.keys(storeStateFns).forEach(fnKey => {
    const fn = storeStateFns[fnKey].bind({$store: store})  //绑定this,因为返回值是this.$store.state,如果不绑定会报错
    storeState[fnKey] = computed(fn)
  })
  return storeState
}

除了调用函数不同,上面的封装有许多共同之处,所有可以合并为一个

mapMutation

setup() {
    const storeMutations = mapMutations(["increment", decrement])
    
    return {
        ...storeMutations
    }
}

action的使用

  • Action提交的是mutation,而不是直接变更状态
  • Action可以包含任意异步操作
  actions: {
    incrementAction(context) {
      setTimeout(() => {
        context.commit('increment');
      }, 1000);
      
    }
  }
  
    methods: {
    increment() {
      this.$store.dispatch('incrementAction')
    },
    decrement() {
      this.$store.commit("decrement");
    }
  }

mapAction使用

与mapState使用相似

  methods: {
    ...mapActions(["incrementAction"]),
    //或者传入对象
    ...mapActions({
        add: "incrementAction"
    }),
  }

对于action,一般是返回一个promise,使得外面可以获取到请求的返回值

    incrementAction(context) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          context.commit('increment');
        }, 1000);
        resolve()
      })
    }

module的使用

为了使代码结构更加清晰,可以使用module 建立一个user.js文件夹

const userModule = {
  state: {
    name: 'juju'
  }
}

export default userModule

在主入口中引入

const store = createStore({
  modules: {
    user
  },

在app.vue中使用

{{ $store.state.user.name }}

当使用模块中的state或mutation时,默认会做一个合并,如果要区分他们的写法,在独立模块中设置namespaced属性

const userModule = {
  namespaced: true,
  state: {
    name: 'juju'
  },
  getters:{
    rename(state, getters, rootState, rootgetters) {
      return state.name + 'hh'
    }
  }
}

export default userModule

取得getter中的数据

{{ $store.getters["user/rename"] }}

调用mutation方法

this.$store.commit("user/increment")

dispatch同理 对于辅助函数的使用,可以采用:

import { createNamespacedHelpers } from 'vuex'
const { mapState, mapGetters, mapMutations } from createNamespacedHelpers('home')


///
...mapActions(["incrementAction"]),

nexttick的使用

将回调推迟到下一个DOM更新周期之后执行,在更改了一些数据以等待DOM更新后立即使用他

import {nextTick} from 'vue'
nextTick(() => {
    //一些操作
})