Vue3 之 Vuex - 状态管理

发布于:2022-10-12 ⋅ 阅读:(196) ⋅ 点赞:(0)

目录

一、概念

1. 状态管理

2. Vuex的状态管理

3. 单一状态树 

二、Vuex 的基本使用 

1. Vuex的安装

2. 创建store

3. 在store文件夹下创建index.js

4. 在main.js中引入 

5. 组件中使用sotre

6. 效果 

三、核心概念 State

1. 直接使用

2. mapState

01 - 使用 

02 - 封装

        useState.js

        使用

四、核心概念 Getters

1. 基本使用

代码

使用

2. getters第二个参数

代码

使用

3. getters的返回函数

代码

使用

4. mapGetters

五、核心概念 Mutations 

六、核心概念 Actions 

七、核心概念 Modules 


一、概念

vue2 契合 vuex      |      vue3 契合 pinia

1. 状态管理

在开发中,应用程序需要处理各种各样的数据,这些数据需要保存在应用程序中的某一个位置,对于这些数据的管理就称之为是状态管理

  • 在Vue开发中,使用组件化的开发方式
  • 而在组件中定义data或者在setup中返回使用的数据,这些数
    据称之为state
  • 在模块template中可以使用这些数据,模块最终会被渲染成
    DOM,称之为View
  • 在模块中会产生一些行为事件,处理这些行为事件时,有可能
    会修改state,这些行为事件称之为actions 

2. Vuex的状态管理

  • 可以考虑将组件的内部状态抽离出来,以一个全局单例的方式来管理
  • 在这种模式下,组件树构成了一个巨大的 “试图View”
  • 不管在树的哪个位置,任何组件都能获取状态或者触发行为
  • 通过定义和隔离状态管理中的各个概念,并通过强制性的规则来维护视图和状态间的独立性,代码会变得更加结构化和易于维护、跟踪

3. 单一状态树 

Vuex 使用单一状态树 : 

  • 一个对象就包含了全部的应用层级的状态
  • 采用的是SSOT,Single Source of Truth,也可以翻译成单一数据源
  • 每个应用将仅仅包含一个 store 实例
    • 单状态树和模块化并不冲突,可以使用module模块

单一状态树的优势 : 

  • 如果状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难
  • 所以Vuex使用了单一状态树来管理应用层级的全部状态
  • 单一状态树能够让我们最直接的方式找到某个状态的片段
  • 而且在之后的维护和调试过程中,也可以非常方便的管理和维护

单一状态树的缺点 : 不够灵活

二、Vuex 的基本使用 

1. Vuex的安装

npm install vuex

2. 创建store

每一个Vuex应用的核心就是store(仓库)

store本质上是一个容器,它包含着你的应用中大部分的状态(state)

Vuex和单纯的全局对象的区别 : 

  • 第一:Vuex的状态存储是响应式的
    • 当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会被更新
  • 第二:不能直接改变store中的状态
    • 改变store中的状态的唯一途径就显示提交 (commit) mutation
    • 这样使得我们可以方便的跟踪每一个状态的变化,从而让我们能够通过一些工具帮助我们更好的管理应用的状态

3. 在store文件夹下创建index.js

// 1. 引入
import { createStore } from 'vuex';

// 2. 创建store对象
const store = createStore({
  // 3. 定义state
  state: () => ({
    // 4. 定义数据
    count: 100
  }),
  // 5. 定义mutations
  mutations: {
    // 6. 定义方法
    increment(state) {
      state.count++;
    }
  }
});

// 5. 导出
export default store;

4. 在main.js中引入 

import { createApp } from 'vue';
import App from './App.vue';
// 1. 导入
import store from './store';
// 2. 使用
createApp(App).use(store).mount('#app');

5. 组件中使用sotre

<template>
  <div class="app">App 页面</div>
  <!-- 1. 模版中使用 -->
  <h2>模版 : {{ $store.state.count }}</h2>
  <h2>computed : {{ storeCount }}</h2>
  <h2>解构count : {{ count }}</h2>

  <button @click="btnClick">增加</button>
</template>

<script setup>
// 2. 在js中使用
import { useStore } from 'vuex';
import { computed, toRefs } from 'vue';

const store = useStore();
console.log(store.state.count);

// 01 - computed包裹一下变成响应式
const storeCount = computed(() => store.state.count);
// 02 - 解构成ref对象
const { count } = toRefs(store.state);

// 监听按钮的点击
const btnClick = () => {
  // 触发mutation,让count++
  store.commit('increment');
};
</script>

6. 效果 

三、核心概念 State

1. 直接使用

<template>
  <div class="app">App 页面</div>
  <!-- 1. 模版中使用 -->
  <h2>模版 : {{ $store.state.count }}</h2>
  <h2>computed : {{ storeCount }}</h2>
  <h2>解构count : {{ count }}</h2>
</template>

<script setup>
// 2. 在js中使用
import { useStore } from 'vuex';
import { computed, toRefs } from 'vue';

const store = useStore();
console.log(store.state.count);

// 01 - computed包裹一下变成响应式
const storeCount = computed(() => store.state.count);
// 02 - 解构成ref对象
const { count } = toRefs(store.state);
</script>

2. mapState

vue3 使用 map之类的,比较麻烦

01 - 使用 

<template>
  <div class="app">App 页面</div>
  <h2>模版 : {{ $store.state.count }}</h2>
  <h2>mapState : {{ cCount }}</h2>

  <button @click="btnClick">改变</button>
</template>

<script setup>
import { useStore, mapState } from 'vuex';
import { computed } from 'vue';

// 1. 拿到store对象
const store = useStore();
// 2. 使用mapState解构出方法
// const { count } = mapState(['count']);
// 数组和对象都可以
const { count } = mapState({
  count: (state) => state.count
});
// 3. 拿到对应的值
/**
 * count => 底层还是通过this.$store.state.count去拿的
 * 因为 setup 中没有this,所以传递过去时需要显示绑定一个$store
 */
const cCount = computed(count.bind({ $store: store }));

const btnClick = () => {
  store.commit('increment');
};
</script>

02 - 封装

        useState.js

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

export default function useState(mapper) {
  // 1. 拿到store对象
  const store = useStore();
  // 2. 使用mapState拿到对应的方法
  const stateFnsObj = mapState(mapper);
  // 4. 定一个接受对象
  const newState = {};
  // 5.遍历
  Object.keys(stateFnsObj).forEach((key) => {
    // 6. 生成绑定过的对象
    newState[key] = computed(stateFnsObj[key].bind({ $store: store }));
  });
  // 7. 返回
  return newState;
}

        使用

<template>
  <div class="app">App 页面</div>
  <h2>模版 : {{ $store.state.count }}</h2>
  <!-- 3. 展示 -->
  <h2>封装哒 : {{ fCount }}</h2>

  <button @click="btnClick">改变</button>
</template>

<script setup>
import { useStore } from 'vuex';
// 1. 导入封装的方法
import useState from './hooks/useState';
// 2. 使用
const { count: fCount } = useState(['count']);

const store = useStore();
const btnClick = () => {
  store.commit('increment');
};
</script>

四、核心概念 Getters

1. 基本使用

代码

import { createStore } from 'vuex';

const store = createStore({
  state: () => ({
    count: 100
  }),
  mutations: {
    increment(state) {
      state.count++;
    }
  },
  // 定义getters
  getters: {
    doubleCount(state) {
      return state.count * 2;
    }
  }
});

export default store;

使用

<template>
  <div class="app">App 页面</div>
  <h2>模版 : {{ $store.state.count }}</h2>
  <!-- 使用getters -->
  <h2>doubleCount : {{ $store.getters.doubleCount }}</h2>

  <button @click="btnClick">改变</button>
</template>

<script setup>
import { useStore } from 'vuex';

const store = useStore();
const btnClick = () => {
  store.commit('increment');
};
</script>

2. getters第二个参数

getters可以接收第二个参数,用来调用其他的getters

代码

import { createStore } from 'vuex';

const store = createStore({
  state: () => ({
    count: 100
  }),
  mutations: {
    increment(state) {
      state.count++;
    }
  },
  getters: {
    doubleCount(state, getters) {
      // 可以调用其他的getters函数
      return state.count * 2 + getters.mathRanDom;
    },
    // 生成[5,50)的随机数
    mathRanDom() {
      return Math.floor(Math.random() * 45) + 5;
    }
  }
});

export default store;

使用

<template>
  <div class="app">App 页面</div>
  <h2>模版 : {{ $store.state.count }}</h2>
  <h2>random : {{ $store.getters.mathRanDom }}</h2>

  <!-- 使用getters -->
  <h2>doubleCount : {{ $store.getters.doubleCount }}</h2>

  <button @click="btnClick">改变</button>
</template>

<script setup>
import { useStore } from 'vuex';

const store = useStore();
const btnClick = () => {
  store.commit('increment');
};
</script>

3. getters的返回函数

getters中的函数本身,可以返回一个函数,可用来接受参数

代码

import { createStore } from 'vuex';

const store = createStore({
  state: () => ({
    count: 100
  }),
  mutations: {
    increment(state) {
      state.count++;
    }
  },
  getters: {
    doubleCount(state, getters) {
      // 可以调用其他的getters函数
      return state.count * 2 + getters.mathRanDom;
    },
    // 生成[5,50)的随机数
    mathRanDom() {
      return Math.floor(Math.random() * 45) + 5;
    },
    countAddNum(state) {
      // 可用来接受传进来的参数
      return function (num) {
        return state.count + num;
      };
    }
  }
});

export default store;

使用

<template>
  <div class="app">App 页面</div>
  <h2>模版 : {{ $store.state.count }}</h2>

  <!-- 基本使用getters -->
  <h2>doubleCount : {{ $store.getters.doubleCount }}</h2>

  <!-- 随机数 -->
  <h2>random : {{ $store.getters.mathRanDom }}</h2>

  <!-- 传递参数 -->
  <h3>countAddNum : {{ $store.getters.countAddNum(10) }}</h3>
  <h3>countAddNum : {{ $store.getters.countAddNum(20) }}</h3>

  <button @click="btnClick">改变</button>
</template>

<script setup>
import { useStore } from 'vuex';

const store = useStore();
const btnClick = () => {
  store.commit('increment');
};
</script>

4. mapGetters

<template>
  <div class="app">App 页面</div>

  <h2>{{ doubleCount }}</h2>

  <button @click="btnClick">改变</button>
</template>

<script setup>
import { computed, toRefs, watch, watchEffect } from 'vue';
import { useStore, mapGetters } from 'vuex';

const store = useStore();
// 1. 第一种方法
// const { doubleCount } = toRefs(store.getters);
// 2. 第二种方法
// const doubleCount = computed(() => store.getters.doubleCount);

// 3. 第三种方法,使用mapGetters
const { doubleCount: doubleCountFn } = mapGetters(['doubleCount']);
const doubleCount = computed(doubleCountFn.bind({ $store: store }));

// 这样时时打印数据
watchEffect(() => {
  console.log(doubleCount.value);
});

const btnClick = () => {
  store.commit('increment');
};
</script>

五、核心概念 Mutations 

六、核心概念 Actions 

七、核心概念 Modules 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到