vuex4结合Vue3的简单使用

1、Vuex介绍

1.1、Vuex 是什么

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

简单说:VueX是个仓库,可以按照一定的规则实现所有组件的数据共享(获取、修改数据),比我们书写的EventBus更加强大。

Vue2 对应的版本:Vuex3

Vue3对应的版本:Vuex4,但实际上Vue3使用的Pinia代替Vuex。

1.2、什么时候使用Vuex

Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。

如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。

简单说:开发大型项目使用Vuex,小型项目EventBus就够用了。

1.3、安装vuex

npm install vuex@next --save

建议在使用vue/cli 脚手架创建项目的时候,直接将vuex选择上,避免自己按照和配置的麻烦。如果使用vite搭建项目,默认是Pinia,需要手动安装vuex。

1.4、关于vuex的仓库

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

简单说:Vuex一个仓库,保存项目中所有组件的共享数据,他不仅仅全局对象,共享的数据具备响应式,需要按照指定的规则修改共享的数据

vuex有个缺点:在刷新页面时,Vuex中的数据会丢失,这是由于刷新会重新加载应用程序,导致Vuex状态的重置。一般在APP端可以禁用页面的刷新功能,PC端无法禁用。

针对PC端解决方案:

1、使用本地存储

2、配合后台程序实现持久化保存

3、使用专门的插件或库来管理应用程序的状态持久化

1.5、5个核心介绍

vuex有5个核心:

  • state : 数据仓库,存放所有组件共享数据
  • mutation:提供对仓库中的数据进行同步修改的方法
  • action:提供对仓库中的数据进行异步修改的方法
  • getter:
  • module:拆分仓库

2、最简单的 Store

2.1、配置vuex

src 下创建store文件夹,其中创建index.js文件,编写vuex的基本配置和初始化操作

// 导入vuex
import { createStore } from "vuex";
// 创建一个新的 store 实例
const store = createStore({
  // 初始化state函数,其中保存的是所有组件共享的数据
  state() {
    return {
      count: 100,
    };
  },
  // 提供修改state中数据的方法
  mutations: {
    add(state) {
      state.count++;
    },
  },
});

// 导出
export default store;

main.js 文件中挂载vuex

import "./assets/main.css";

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

const app = createApp(App);

app.use(router);
// 将 store 实例作为插件安装
app.use(store);

app.mount("#app");

2.2、使用vuex

views文件夹 下 创建 Hello.vue文件 ,获取Vuex中的数据

<template>
  <div>
    <p>msg:{{ msg }}p>
    <p>vuex中的count:{{ count }}p>
  div>
template>

<script>
export default {
  data() {
    return {
      msg: "演示vuex的使用",
      count: 0,
    };
  },
  // 在vue实例初始化完成后,获取vux中的数据
  created() {
    // 由于已经将Vuex的实例绑定在app组件上,可以通过this直接获取
    // this.$store 即可获取到vuex的实例
    console.log(this.$store.state.count);
    this.count = this.$store.state.count;
  },
};
script>

<style scoped>style>

2.3、修改数据

views文件夹 下 创建 world.vue 文件,调用vuex的 mutations 中提供的 add 方法完成数据修改操作

<template>
  <div>
    <button @click="changeData">修改vuex中的数据button>
  div>
template>

<script>
export default {
  methods: {
    changeData() {
      this.$store.commit("add");
      //   其实直接修改也是可以的,但是不推荐这个操作
      this.$store.state.count = 200;
    },
  },
};
script>

<style scoped>style>

再次强调,我们通过提交 mutation 的方式,而非直接改变 store.state.count,是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显,这样你在阅读代码的时候能更容易地解读应用内部的状态改变。此外,这样也让我们有机会去实现一些能记录每次状态改变,保存状态快照的调试工具。有了它,我们甚至可以实现如时间穿梭般的调试体验。

由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的 methods 中提交 mutation。

简单说:通过mutation 中的方法,可以实现共享数据的可控性

3、vuex的详细介绍

Vuex有5个核心概念:state、getters、mutations、actions、modules

小小提示:操作vuex的仓库时,基本都提供两种方式:直接操作辅助函数

3.1、核心state

  • 作用: 多个组件需要共享的数据, 入库, 放在state里面.

  • 组件中如何获取到state的数据呢?

3.1.1、编辑需要共享的数据

// 导入vuex
import { createStore } from "vuex";
// 创建一个新的 store 实例
const store = createStore({
  // 初始化state函数,其中保存的是所有组件共享的数据
  state() {
    return {
      count: 100,
      user: {
        name: "张无忌",
        age: 23,
        sex: "男",
        addr: "冰火岛",
      },
    };
  },
  // 提供修改state中数据的方法
  mutations: {
    add(state) {
      state.count++;
    },
  },
});

// 导出
export default store;

3.1.2、直接获取数据

在需要使用vuex中共享数据的页面,使用 this.$store.state.共享数据key值 即可直接获取共享数据

<template>
  <div>
    <p>{{ count }}p>
    <p>{{ user }}p>
  div>
template>

<script>
export default {
  // 在vue实例初始化完成后,获取vux中的数据
  created() {
    console.log(this.$store);
    console.log(this.$store.state.count);
    console.log(this.$store.state.user);
  },
  // 通过计算属性,返回数据
  computed: {
    count() {
      return this.$store.state.count;
    },
    user() {
      return this.$store.state.user;
    },
  },
};
script>

<style scoped>style>

3.1.3、mapState辅助函数

vuex提供mapState辅助函数,更加快捷,灵活的获取vuex中共享的数据,辅助函数有两种书写方式

<template>
  <div>
    <p>{{ count }}p>
    <p>{{ user }}p>
  div>
template>

<script>
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from "vuex";
export default {
  // 通过计算属性,返回数据
  computed: {
    // 对象方式
    // ...mapState({
    //   count: (state) => state.count,
    //   user: (state) => state.user,
    // }),
    // 数组方式
    ...mapState(["count", "user"]),
  },
};
script>

<style scoped>style>

3.2、核心mutations

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

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。

3.2.1、编辑mutation中的方法

// 导入vuex
import { createStore } from "vuex";
// 创建一个新的 store 实例
const store = createStore({
  // 初始化state函数,其中保存的是所有组件共享的数据
  state() {
    return {
      count: 100,
      user: {
        name: "张无忌",
        age: 23,
        sex: "男",
        addr: "冰火岛",
      },
    };
  },
  // 提供修改state中数据的方法
  mutations: {
    // state,就是仓库对象
    // payload修改的值
    // 一般为了区分,会将这些方法名全部大写
    CHANGE_COUNT(state, payload) {
      console.log("在仓库中,CHANGE_COUNT执行,", state, payload);
      state.count += payload;
    },

    CHANGE_USER(state, payload) {
      state.user.age += payload.num;
    },
  },
});

// 导出
export default store;

3.2.2、直接进行修改

使用commit来完成直接修改,this.$store.commit(“函数名”,数据)

<template>
  <div>
    <p>{{ count }}p>
    <p>{{ user }}p>
    <button @click="updateCount">修改countbutton>
  div>
template>

<script>
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState, mapMutations } from "vuex";
export default {
  // 通过计算属性,返回数据
  computed: {
    ...mapState(["count", "user"]),
  },
  methods: {
    updateCount() {
      // 直接调用方法修改
      // this.$store.commit("CHANGE_COUNT", 3);
      // 采用对象方式修改
      this.$store.commit({
        type: "CHANGE_COUNT",
        num: 3,
      });
    },
  },
};
script>

<style scoped>style>

若采用对象方式修改,payload接收到的是一个对象,需要处理。

CHANGE_COUNT(state, payload) {
    console.log("在仓库中,CHANGE_COUNT执行,", state, payload);
    state.count += payload.num;
},

3.2.3、辅助函数修改

vuex中提供 mapMutations 对象来辅助修改数据 , 由于是辅助函数修改,在事件中直接书写修改的函数名并传递参数

<template>
  <div>
    <p>{{ count }}p>
    <p>{{ user }}p>
    <button @click="CHANGE_COUNT(4)">修改countbutton>
    <button @click="changeNum(5)">修改countbutton>
  div>
template>

<script>
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState, mapMutations } from "vuex";
export default {
  // 通过计算属性,返回数据
  computed: {
    ...mapState(["count", "user"]),
  },
  methods: {
    // 辅助函数,修改数据
    ...mapMutations(["CHANGE_COUNT"]),
    // 辅助函数,采用对象方式修改
    ...mapMutations({
      changeNum: "CHANGE_COUNT",
    }),
  },
};
script>

<style scoped>style>

3.3、核心getters[重点]

作用: 相当于仓库中的计算属性, 对state进行二次处理,和state的作用几乎一样

3.3.1、准备数据

// 导入vuex
import { createStore } from "vuex";
// 创建一个新的 store 实例
const store = createStore({
  // 初始化state函数,其中保存的是所有组件共享的数据
  state() {
    return {
      count: 100,
      user: {
        name: "张无忌",
        age: 23,
        sex: "男",
        addr: "冰火岛",
      },
      vipArr: [
        { name: "张无忌", age: 23 },
        { name: "张三丰", age: 80 },
        { name: "金毛狮王", age: 60 },
        { name: "成昆", age: 60 },
      ],
    };
  },
  // 仓库中的计算属性
  getters: {
    // 对vips数据进行处理,过滤器年龄超过60岁的人
    vips(state) {
      return state.vipArr.filter((v) => v.age >= 60);
    },
  },
  // 提供修改state中数据的方法
  mutations: {
    // state,就是仓库对象
    // payload修改的值
    // 一般为了区分,会将这些方法名全部大写
    CHANGE_COUNT(state, payload) {
      console.log("在仓库中,CHANGE_COUNT执行,", state, payload);
      state.count += payload;
    },

    CHANGE_USER(state, payload) {
      state.user.age += payload.num;
    },
  },
});
// 导出
export default store;

3.3.2、直接获取数据

getters 本身就是对数据进行二次处理的,没有辅助函数方式

<template>
  <div>
    <h3>花甲之年,华山之巅h3>
    <p v-for="v in vips" :key="v.name">{{ v }}p>
  div>
template>

<script>
import { mapGetters } from "vuex";
export default {
  // 获取vuex数据,建议使用计算属性,更加便捷
  computed: {
    ...mapGetters(["vips"]),
  },
  created() {
    // 直接通过属性访问
    console.log(this.$store.getters.vips);
  },
};
script>

<style lang="less" scoped>style>

3.4、核心actions [重点]

作用: 异步修改数据. mutations修改数据是同步的. 如果想要异步修改数据, 就放在actions中.

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

3.4.1、准备数据

// 导入vuex
import { createStore } from "vuex";
// 创建一个新的 store 实例
const store = createStore({
  // 初始化state函数,其中保存的是所有组件共享的数据
  state() {
    return {
      count: 100,
      user: {
        name: "张无忌",
        age: 23,
        sex: "男",
        addr: "冰火岛",
      },
      vipArr: [
        { name: "张无忌", age: 23 },
        { name: "张三丰", age: 80 },
        { name: "金毛狮王", age: 60 },
        { name: "成昆", age: 60 },
      ],
      // 空数组 商品数据
      goods: [],
    };
  },
  // 仓库中的计算属性
  getters: {
    // 对vips数据进行处理,过滤器年龄超过60岁的人
    vips(state) {
      return state.vipArr.filter((v) => v.age >= 60);
    },
  },
  actions: {
    // 异步修改数据
    // context 相当于 this.$store
    // payload 数据
    ASYNC_SET_GOODS(context, payload) {
      setTimeout(() => {
        context.commit("SET_GOODS", payload);
      }, 2000);
    },
  },
  // 提供修改state中数据的方法
  mutations: {
    SET_GOODS(state, payload) {
      // 同步修改数据
      state.goods = payload;
    },
    // state,就是仓库对象
    // payload修改的值
    // 一般为了区分,会将这些方法名全部大写
    CHANGE_COUNT(state, payload) {
      console.log("在仓库中,CHANGE_COUNT执行,", state, payload);
      state.count += payload;
    },

    CHANGE_USER(state, payload) {
      state.user.age += payload.num;
    },
  },
});

// 导出
export default store;

其实不用actions,直接在mutations也可以完成异步修改数据的。只是actions是专门设计出来用于进行异步修改。

而在actions中最终还是需要使用mutations中的方法修改数据

3.4.2、 直接 dispatch 触发

触发修改数据与 mutations 修改基本一致,只需要将commit修改为dispatch即可

this.$store.dispatch ("函数名1", 数据);

this.$store.dispatch ({
  type: '函数名1',
  数据
});

3.4.3、通过辅助函数触发

import { mapActions } from 'vuex';

export default {
  methods: {
    ...mapActions(["函数名"]) // 数组写法
    ...mapActions({ // 对象的写法
       键名: "函数名" 
    })
  }
}

3.5、核心modules

作用: 拆分仓库, 把一个仓库拆分成几份

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割

3.5.1、拆分仓库

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

3.5.2、获取数据

获取数据的时候,在正常操作的时候,加上模块名即可

this.$store.state.模块名.count

3.5.3、修改数据

this.$store.commit("模块名/函数名", 数据)

你可能感兴趣的:(javascript,前端,vue.js)