Vue3实践和对vuex中mapState,mapGetters辅助函数封装

1. readonly API的使用

在我们传递给其他组件数据时,如果直接将响应式数据传递给子组件。子组件如果使用数据不规范,修改了父组件传进来的props值没有任何反馈。

// 父组件
// <ReadonlyChild :info="info" />

setup() {
    const info = reactive({
      name: "哇哈哈",
    });
    return {
      info,
    };
}
// 子组件
setup(props) {
    const onChangeInfo = () => {
      const info = props.info;
      // 修改父组件传来的props 没有任何反馈。
      info.name = "woowow";
    };
    return {
      onChangeInfo,
    };
}

开发中我们往往希望其他组件使用我们传递的内容,但是不允许它们修改时,就可以使用 readonly了。

// 父组件
// <ReadonlyChild :info="infoReadonly" />

setup() {
    const info = reactive({
      name: "哇哈哈",
    });
    const infoReadonly = readonly(info);
    const onChangeInfo = () => {
      // 在父组件中可修改info中的值,子组件依然可响应更新
      info.name = "父组件给你的值";
    };
    return {
      infoReadonly,
      onChangeInfo
    };
}
// 子组件
setup(props) {
    const onChangeInfo = () => {
      const info = props.info;
      // 此时修改props时,控制台会有一个警告:
      // Set operation on key "name" failed: target is readonly. 
      info.name = "woowow";
    };
    return {
      onChangeInfo,
    };
}

2. 响应式变量直接解构会失去响应性

将响应式变量直接解构会失去其响应性

const info = reactive({ age: 18 });
// 直接解构后 age 值失去响应性,当 onChangeAge 函数触发时,age值不在变,而ageRef 依然具有响应性
const { age } = info;
const { age: ageRef } = toRefs(info);
const onChangeAge = () => {
  info.age++;
};

3. watchEffect 清除副作用

watchEffect API 可自动收集依赖项,当依赖项改变时触发侦听器函数。当我们在侦听器函数执行额外的副作用函数,例如:发送网络请求时。每当依赖性项变更都会发起一个新的网络请求,那么上一次的网络请求应该被取消掉。这个时候我们就可以清除上一次的副作用了。

setup() {
    const count = ref(0);

    const onChangeCount = () => {
      count.value++;
    };

    watchEffect((onInvalidate) => {
      // 侦听器函数中需要发起网络请求,用setTimeout模拟
      const timer = setTimeout(() => {
        console.log("请求成功啦");
      }, 2000);

      // 在侦听器函数重新执行时触发onInvalidate函数
      onInvalidate(() => {
        // 在这个函数中清除请求
        clearTimeout(timer);
        console.log("onInvalidate 回调触发");
      });

      // 自动收集count的依赖
      console.log("count-在改变", count.value);
    });

    return {
      count,
      onChangeCount,
    };
  }

4. setup 函数访问Vuex中Store数据

4.1 使用mapState辅助函数

通常需要通computed函数来获取state中数据,并保存响应性。

setup() {
    const store = useStore();
    // 在setup中要获取store中的state。如果state非常多,无疑这样做很繁琐
    const uName = computed(() => store.state.name);
    const uAge = computed(() => store.state.age);
    const uHeight = computed(() => store.state.height);
    /**
     * 直接使用mapState辅助函数得不到想要的结果
     * 这样获取的storeState 是一个 { name:  function mappedState (){...}, age: function mappedState (){...}, height: function mappedState (){...} } 这样的对象
     */
    const storeState = mapState(["name", "age", "height"]);
    // 需要对返回值进行处理
    const resStoreState = {};
    Object.keys(storeState).forEach((fnKey) => {
      const fn = storeState[fnKey].bind({ $store: store });
      resStoreState[fnKey] = computed(fn);
    });

    return {
      uName,
      uAge,
      uHeight,
      ...resStoreState,
    };
  }

封装成hooks如下:

// useState.js
import { computed } from "vue";
import { useStore, mapState } from "vuex";

export default function useState(mapper) {
  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;
}

在组件中使用时

import useState from "@/hooks/useState";


setup() {
    // 数组用法
    const state = useState(["name", "age", "height"]);

    // 对象用法,可使用别名
    const stateObj = useState({
      uName: (state) => state.name,
      uAge: (state) => state.age,
      uHeight: (state) => state.height,
    });
    return {
      ...state,
      ...stateObj,
    };
  }

4.2 mapGetters 辅助函数的封装

其原理与mapState 函数封装类似

// useGetters.js
import { computed } from "vue";
import { mapGetters, useStore } from "vuex";

export default function useGetters(mapper: any) {
  const store = useStore();
  const storeGettersFns = mapGetters(mapper);
  const storeGetters = {};
  Object.keys(storeGettersFns).forEach((fnKey) => {
    const fn = storeGettersFns[fnKey].bind({ $store: store });
    storeGetters[fnKey] = computed(fn);
  });
  return storeGetters;
}

useStateuseGetters两个函数相似度很高,在进一下封装

// useMapper.js
import { computed } from "vue";
import { useStore } from "vuex";

export default function useMapper(mapper, mapFn) {
  const store = useStore();
  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.js
import { mapState } from "vuex";
import useMapper from "./useMapper";

export default function useState(mapper) {
  return useMapper(mapper, mapState);
}

// useGetters.js
import { mapGetters } from "vuex";
import useMapper from "./useMapper";

export default function useGetters(mapper: any) {
  return useMapper(mapper, mapGetters);
}

4.3 对module的支持

useStateuseGetters 函数暂时还不支持传入命名空间,进一步封装。 useMapper的封装保持不变。

// useState.js
import { createNamespacedHelpers, mapState } from "vuex";
import useMapper from "./useMapper";

export default function useState(mapper, moduleName) {
  let mapperFn = mapState;
  if (typeof moduleName === "string" && moduleName.length > 0) {
    mapperFn = createNamespacedHelpers(moduleName).mapState;
  }
  return useMapper(mapper, mapperFn);
}

// useGetters.js
import { createNamespacedHelpers, mapGetters } from "vuex";
import useMapper from "./useMapper";

export default function useGetters(mapper, moduleName) {
  let mapperFn = mapGetters;
  if (typeof moduleName === "string" && moduleName.length > 0) {
    mapperFn = createNamespacedHelpers(moduleName).mapGetters;
  }
  return useMapper(mapper, mapperFn);
}

// 在组件中的使用
// Home.vue
setup() {
  const state = useState(["homeCounter"], "home");

  const stateGetter = useGetters(["doubleHomeCounter"], "home");

  return {
    ...state,
    ...stateGetter,
  }
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3,你可以使用Vuex辅助函数来简化在组件使用Vuex的操作。下面是使用Vuex辅助函数的步骤: 首先,确保已经安装了VuexVue 3。 在你的Vue 3项目,创建一个store文件夹,并在其创建一个store.js文件。在store.js文件,你可以定义你的Vuex store,包括状态(state)、mutations、actions等。 ```javascript // store.js import { createStore } from 'vuex'; const store = createStore({ state: { // 状态 }, mutations: { // 修改状态的方法 }, actions: { // 异步操作的方法 }, }); export default store; ``` 在你的根组件(App.vue),使用`createApp`函数创建Vue实例时,将store传递给`use`方法,这样整个应用程序都可以访问到store。 ```javascript // App.vue import { createApp } from 'vue'; import store from './store'; createApp(App).use(store).mount('#app'); ``` 现在,你可以在任何组件使用Vuex辅助函数来访问store的状态和触发mutations或actions。 在组件,你可以使用`mapState`辅助函数来将store的状态映射到组件的计算属性。 ```javascript // MyComponent.vue import { mapState } from 'vuex'; export default { computed: { ...mapState(['stateProperty']), }, }; ``` 你也可以使用`mapMutations`辅助函数来将mutations映射到组件的methods,以便在组件触发mutations。 ```javascript // MyComponent.vue import { mapMutations } from 'vuex'; export default { methods: { ...mapMutations(['mutationName']), }, }; ``` 最后,你可以使用`mapActions`辅助函数将actions映射到组件的methods,以便在组件触发actions。 ```javascript // MyComponent.vue import { mapActions } from 'vuex'; export default { methods: { ...mapActions(['actionName']), }, }; ``` 这样,你就可以在Vue 3使用Vuex辅助函数来简化在组件使用Vuex了。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值