vue3+typescript【9】

VUEX

组件获取状态(State)

如果我们有很多个状态都需要获取话,可以使用mapState的辅助函数:
import { mapState } from 'vuex
mapState返回的是一个对象,加’…'表示将函数内容变成computed格式,即此时返回的是一个个函数,computed返回的是ref对象

option api使用
  • mapState的方式一:对象类型;
...mapState({
    sCounter:state => state.counter,
    sName: state => state.name
})
  • mapState的方式二:数组类型;
...mapState(["counter", "name"])
  • 也可以使用展开运算符和来原有的computed混合在一起;
composition api使用

在setup中如果我们单个获取装是非常简单的:

  • 通过useStore拿到store后去获取某个状态即可
import { useStore } from 'vuex';
import { computed } from 'vue';
setup(){
    const store = useStore();
    const sCounter = computed(()=> store.state.counter);
}
setup(){
    const state = useStore({
        name: state => state.name,
        age: state => state.age
    })
    return {
        ...state
    }
}
  • 使用mapstate
setup(){
    const store = useStore();
    const storeStateFns = mapState(["counter", "name", "age"]);
    const storeState = {};
    Object.keys(storeStateFns).forEach(fnKey => {
        const fn = storeStateFns[fnKey].bind({$store:store});
        storeState[fnKey] = computed(fn)
    })
    return{
        ...storeState
    }
}

bind的用法举栗:

function abc(){
    console.log(this);
}
cosnt foo = abc.bind({name:"hahaha"});
foo();

封装

import { useState } from '../hooks/useState'
export default {
    setup(){
        const storeState = useState(["counter", "name"])
        return{
            ...storeState
        }
    }
}

---------useState.js

import { useStore, mapState } from 'vuex';
import { computed } from 'vue';
export function useState(mapper){
    const store = useStore();
    const storeStateFns = mapState(["counter", "name", "age"]);
    const storeState = {};
    Object.keys(storeStateFns).forEach(fnKey => {
        const fn = storeStateFns[fnKey].bind({$store:store});
        storeState[fnKey] = computed(fn)
    })
    return storeState
}

getters

某些属性我们可能需要警告变化后来使用,这个时候可以使用getters

option API
computed:{
    ...mapGetters(["totalPrice", "myName"]),
    ...mapGetters({
        finalPrice: "totalPrice",
        finalName: "myName"
    })
}
composition api
import{ useStore, mapGetters } from 'vuex';
import{ computed } from 'vue';
export function useGetters(mapper){
    const store = useStore();
    const stateFns = mapGetters(mapper);
    const state = {}
    Object.keys(stateFns).forEach(fnKey => {
        const fn = stateFns[fnKey].bind({$store:store});
        state[fnKey] = computed(fn)
    })
    return state
}

Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation

mutations:{
    add(state, payload){
        state.counter += payload.count
    }
}

payload为对象类型
对象风格的提交方式

$store.commit({
    type:"add",
    count:100
})
mapMutations

此时setup和methods的使用方法一致,可以帮助我们快速映射到对应的方法中

...mapMutations({
    add: "add"
})
//...mapMutations(["add"])
Mutation重要原则

一条重要的原则就是要记住 mutation 必须是同步函数

  • 这是因为devtool工具会记录mutation的日记;
  • 每一条mutation被记录,devtools都需要捕捉到前一状态和后一状态的快照;
  • 但是在mutation中执行异步操作,就无法追踪到数据的变化;
  • 所以Vuex的重要原则中要求 mutation必须是同步函数

action

Action类似于mutation,不同在于:

  • Action提交的是mutation,而不是直接变更状态;
  • Action可以包含任意异步操作
mutations:{
    increment(state){
        state.counter++;
        //可以直接改变state数据
    }
}
actions:{
    increment(context){
        context.commit("increment");
        //要通过提交事件触发mutation改变状态
    }
}
actions的分发操作

分发使用的是 store 上的dispatch函数

add(){
    //this.$store.dispatch("increment");
    //this.$store.dispatch("increment",{counter:100});
    this.$store.dispatch({
            type:"increment",
            count:100
        });
}
actions的辅助函数
  1. option API
methods:{
    ...mapActions(["increment"]),
    ...mapActions({
        add:"increment"
    })
}
  1. composition API
const actions1 = mapActions(["increment"]);
const actions2 = mapActions({
        add:"increment"
    });
actions的异步操作

可以通过让action返回Promise,在Promise的then中来处理完成后的操作

actions:{
    increment(context) {
        return new Promise((resolve) => {
            setTimeout(() => 
                context.commit("increment")
                resolve("异步完成")
            },1000);
        })
    }
}
const store = useStore();
const increment = ()=>{
    store.dispatch("increment").then(res=>{
        console.log(res, "异步完成")
    })
}

action的第一个context参数可以解构成:
({commit, dispatch, state, rootState, getters, rootGetters})
getter有四个参数:
(state, getters, rootState, rootGetters)

如果希望在action中修改root中的state:

commit("changeName", null, {root:true})
//此时第二个参数是外来参数,是一个对象
dispatch("changeName", null, {root:true})

module

对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象

命名空间

默认情况下,模块内部的action和mutation仍然是注册在全局的命名空间中的:

  • 这样使得多个模块能够对同一个 action 或 mutation 作出响应;
  • Getter 同样也默认注册在全局命名空间;
    但此时会出现同名函数或变量同时响应,所以可以采用命名空间来使模块具有更高的封装度和复用性。
    ---------可以添加 namespaced: true 的方式使其成为带命名空间的模块:
  • 当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名
辅助函数

module的辅助函数mapState,mapGetters,mapMutations,mapActions有三种使用方法:

  • 方式一:通过完整的模块空间名称来查找;
computed:{
    ...mapState({
        a:(state) => state.some.nested.module.a,
    })
},
methods:{
    ..mapActions([
        "some/nested/module/foo",
    ])
}
  • 方式二:第一个参数传入模块空间名称,后面写上要使用的属性;
computed:{
    ...mapState("some/nested/module",{
        a:(state) => state.a,
    })
},
methods:{
    ..mapActions("some/nested/module",[
        "foo",
    ])
}

  • 方式三:通过 createNamespacedHelpers 生成一个模块的辅助函数
import {mapState, mapActions} = createNamespacedHelpers('some/nested/module')
export default{
    computed:{
    ...mapState({
        a:(state) => state.a,
    })
},
methods:{
    ..mapActions([
        "foo",
    ])
}
}

composition API写法:

setup(){
    <!-- const state = mapState(["homeCounter"]) -->
    <!-- const getters = mapGetters(["doubleHomeCounter"]) -->
    <!-- 这里由于前面已经封装过对应的hook所以只要引入使用即可,最好给第一个参数指明模块 -->
    const state = useState(["home","homeCounter"])
    const getters = useGetters(["home","doubleHomeCounter"])

    const mutations = mapMutations(["increment"])
    const actions = mapActions(["incrementAction"])

    return{
        ...state,
        ...getters,
        ...mutations,
        ...actions
    }
}

useState和useGetters支持模块化封装

前面封装的hook是不能对模块使用的

<!-- useMapper.js -->
import {computed} from 'vue'
import {mapState, useStore} from 'vuex'

export function useMapper(mapper, mapFn){
    <!-- 拿到store对象 -->
    const store = useStore()
    <!-- 获取到对应的对象的function    {name: function, age:function} -->
    const storeStateFns = mapFn(mapper)
    <!-- 对数据进行转换 -->
    const storeState = {}
    Object.keys(storeStateFns).forEach(fnKey => {
        const fn = storeStateFns[fnKey].bind({$store:store});
        storeState[fnKey] = computed(fn)
    })

    return storeState
}

useState的修改

<!-- useState.js -->
import { mapState, createNamespacedHelpers } from 'vuex'
import { useMapper } from './useMapper'

export function useState(moduleName, mapper){
    let mapperFn = mapState
    if(typeof moduleName === 'string' && moduleName.length>0) {
        mapperFn = createNamespacedHelpers(moduleName).mapState
    }

    return useMapper(mapper,mapperFn)
}

useGetters的修改

<!-- useGetters.js -->
import { mapGetters, createNamespacedHelpers } from 'vuex'
import { useMapper } from './useMapper'

export function useGetters(moduleName, mapper){
    let mapperFn = mapGetters
    if(typeof moduleName === 'string' && moduleName.length>0) {
        mapperFn = createNamespacedHelpers(moduleName).mapGetters
    }

    return useMapper(mapper,mapperFn)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值