vuex在vue3中的使用汇总学习

125 阅读3分钟

1:创建store

import { cretaeStore } from "vuex"
import aModule from './a.js' // 其他的store
const changeInfo = 'changeInfo'
const store = createStore({
  state:() => ({
  	counter: 0,
    friends: [
      {name: "haha", id: 1},
      {name: "hehe", id: 2},
    ]
  }),
  mutations: {
    increment(state, payload){ //  传递的参数会携带在payload中
      state.counter += payload; // 修改对应的state 
    },
    // 将方法抽离成常量,使用时需要用计算属性
    [changeInfo](state, payload){}
  },
  getters: {
    // getters: 可以调用其他的getters
    doubleCount(state, getters) {
      return state.count + getters.myCount + rootState.rootCounter
    },
    myCount(state){
      return state.count; // 没啥用,举个例子而已
    },
    getFriendsById(state){
      return function (id) {
        return state.friends.find(item => item.id === id);
      }
    }
  },
  actions: {
    // 异步函数自动返回promise
    incrementAction(context, payload) {
      return new Promise(async (resolve, reject) => {
        const res = await fetch("http://xxx");
        const data = await res.json();
        context.commit("increment", data);
        resolve("succ: ", data);
      })      
    }
  },
  modules: {
    a: aModule
  }
})
export default store 

2: 在main中导入并use store

Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中

  1. 在根组件中注入所有子组件:把 store 对象提供给 “store” 选项
// 官方通过new Vue创建
const app = new Vue({
  el: '#app',
  // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})
// 通过createApp创建
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
// use store
createApp(App).use(store).mount('#app')

3: 在子组件中使用store

// 1模板中
$store.state.counter

// 2方法中 setup
import { useStore } from "vuex"
const store = useStore();
store.state.counter // 直接修改这个是可以成功的,但是不建议这么做
store.commit("increment") // 修改counter
	// 如何简写store.state.counter => 使用toRefs
const {counter} = toRefs(store.state) //  {{counter}} 保持响应式

// 3方法中 option
	// 1. 通过computed 简写 store中的state属性,模板中直接 {{storeCounter}} 使用
computed: {
  storeCounter() {
    return this.$store.state.counter.count;
  },
},

3.1 mapstate -- 映射函数

3方法中 optionApi 每个使用computed写一遍太繁琐了,所以有了这玩意

3.1.1 option Api中使用
import { mapState } from 'vuex';
// 1.模板中使用
{{ count }} --- {{ sCount }}
// 2.计算属性中混入
computed: {
  ...mapState(["count"]),
  ...mapState({ // 如果store中的属性和组件data中的属性重名了,重名的需要写成对象形式
      sCount: state => state.count,
      // ... 如果有其他的,则继续写
  })
},
3.1.2 setup中使用
// 1.模板中使用
{{ sCount }}
// 2.mapState返回一个函数,使用copmuted执行这个函数,但是由于mapState底层用的是this.$store,而setup没有this,所以需要绑定useStore中的this
import {computed} from "vue";
import {mapState, useStore} from "vuex"
const {count} = mapState(["count"]); // return fn
const store = useStore();
const sCount = computed(count.bind({ $store: store }));
// 这种做法太繁琐,直接用toRefs + 解构完事了

4: getters

store 中定义“getter”(可以认为是 store 的计算属性)。

就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

// 模板中使用
{{ $store.getters.doubleCount }} --- {{ $store.getters.getFriendsById(1) }}

让 getter 返回一个函数的简写方式:

(在通过方法访问时,每次都会去进行调用,而不会缓存结果。)

image-20240220210512024

4.1 mapGetters -- 映射函数

4.1.1 option api中使用
// 1. 模板中使用
{{ doubleCount}} ---- {{getFriendsById(1)}}

// 2. 映射
import { mapGetters } from 'vuex'
export default {
  computed: {
    ...mapGetters(["doubleCount", "getFriendsById"]),
  }
}
4.1.2 setup
// 1.模板中使用
{{ sDoubleCount }}
// 2. 映射
import {computed} from "vue";
import {mapGetters, useStore} from "vuex"
const { doubleCount } = mapGetters(["doubleCount"]); // return fn
const store = useStore();
const sDoubleCount = computed(doubleCount.bind({ $store: store }));
// 这种做法太繁琐,直接用toRefs + 解构完事了

// 3. 方法2:toRefs + 解构 => 包装成ref 
const { doubleCount } = toRefs(store.getters)

// 4. 方法3:如果是争对某个getters属性使用computed
const doubuleCount = computed(() => store.getters.doubuleCount)

5: mutations

用于修改state 的数据

通过commit 派发

// 1模板中
$store.state.counter

// 2.方法中 setup
import { useStore } from "vuex"
const store = useStore();
store.commit("increment") // 修改counter

// 3.方法中 option
this.$store.commit("increment", payload)

5.1 mapMutations

5.1.1 option
// 使用
@click="increment(payload)"

// 映射
import { mapMutations } from 'vuex'
import { CHANGE_INFO } from "@/store/mutation_types"

export default {
  methods: {
   ...mapMutations(["increment"])
  }
}
5.1.2 compositon
// 使用
@click="increment(payload)"

// 映射
import { mapMutations, useStore } from 'vuex'
const store = useStore()
// 1.手动的映射和绑定
const mutations = mapMutations(["increment"])
const newMutations = {}
Object.keys(mutations).forEach(key => {
  dnewMutations[key] = mutations[key].bind({ $store: store })
})
const { increment } = newMutations;

6: actions

通过dispatch 派发

// 模板显示
{{ $store.state.counter }}

// option api 派发action
this.$store.dispatch("incrementAction", payload);

// compositon api 派发action
const store = useStore();
function increment() {
    store.dispatch("incrementAction",payload).then(res => {
    // 可以在这里监听函数执行
    clg(res);
  })
}

6.1 mapActions

6.1.1 option
// 模板使用
 @click="incrementAction(payload)"

// 映射
import { mapActions } from 'vuex'
export default {
  methods: {
    ...mapActions(["incrementAction"])
  }
}
6.1.2 composition api
import { useStore, mapActions } from 'vuex'
const store = useStore()

// 1.在setup中使用mapActions辅助函数
const actions = mapActions(["incrementAction", "changeNameAction"])
const newActions = {}
Object.keys(actions).forEach(key => {
  newActions[key] = actions[key].bind({ $store: store })
})
const { incrementAction, changeNameAction } = newActions 

7: modules

在a.js中

默认情况下,action / mutation / getter 默认注册在全局命名空间 => 重名的方法会导致bug

export default {
  namespaced: true, // 开启自己的命名空间
  state: () => ({
    // 服务器数据
    banners: [],
  }),
  getters: {
  	aSdoubleCount(state, getters, rootState) {
      return state.count + getters.myCount + rootState.counter
    },
  },
  mutations: {},
  actions: {
  	// context 中可以结构出六个参数
    incrementCountAction({commit, dispatch, state, rootState, getters, rootGetters}){
      // 修改根store中的数据
      commit("increment", null, {root: true});
    }
  }
}
// 如果是a中的数据
// 使用时需要从模块中获取
{{ store.state.a.banners}}

// 除了state的数据,其他会被合并在一起
{{ $store.getters.aSdoubleCount}}

// 开启了命名空间后
{{ $store.getters["a/aSdoubleCount"]}}
store.dispatch("a/incrementCountAction")

其他

vuex官方文档