vue2(Vuex)、vue3(Pinia)、react(Redux)状态管理

news2024/11/16 0:39:37

vue2状态管理Vuex

Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它使用集中式存储管理应用的所有组件的状态,以及规则保证状态只能按照规定的方式进行修改。

  • State(状态):Vuex 使用单一状态树,即一个对象包含全部的应用层级状态。这个状态树对应着一个应用中的所有状态。
  • Getters(获取器):Getters 允许你在模板中计算状态。相当于组件中的计算属性。可以对 state 中的数据进行处理和过滤。
  • Mutations(变更):Mutations 是 Vuex 修改状态的唯一方式,它们是同步事务。每个 mutation 都有一个字符串类型的事件类型 (type) 和 一个回调函数,该回调函数接受 state 作为其第一个参数。
  • Actions(动作):Actions 类似于 Mutations,不同之处在于它们是异步的。Actions 提交 Mutations 来修改状态。Actions 可以包含任意异步操作。
  • modules(模块):Vuex 允许将 store 分割成模块,每个模块都有自己的 state、mutations、actions、getters。

辅助函数:便于在组件中使用 Vuex 的功能

  • mapState: 将 store 中的 state 映射为组件的计算属性。
  • mapGetters: 将 store 中的 getters 映射为组件的计算属性。
  • mapMutations: 将 store 中的 mutations 映射为组件的方法。
  • mapActions: 将 store 中的 actions 映射为组件的方法。

1、创建vue2项目

安装脚手架:npm install -g @vue/cli
创建vue2项目:vue create vue2_myapp
(输入完命令后选择vue2)

2、安装Vuex依赖
在项目中使用npm或者yarn安装Vuex。

npm install vuex
yarn add vuex
npm install vuex@^3.5.0 --save(指定版本使用)

3、在src目录下创建store目录,在下面创建js用于存储Vuex(命名通常为index.js或者store.js)

// store.js
import Vue from 'vue';
import Vuex from 'vuex';
import modulesA from './modules/modulesA'

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    //存储公共数据
    count: 100,
  },  
  mutations: {
    // 定义修改state数据的方法
    increment(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    },
  },
  actions: {
    // 使用异步的方式来触发mutations中的方法进行提交
    
  },
  getters: {
    // 获取状态的方法
    getCount: (state) => state.count,
  },
  modules: {
    // 注册拆分的模块
    a:{
      //namespaced: true,//可以直接在modulesA配置在中
      ...modulesA
    }
  }
});

当项目比较复杂时,可以在src/store下增加module,将数据拆成模块,下面举一个moduleA示例

// moduleA.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

//注意此处是导出一个模块不是new一个新vuex
export default{
  namespaced: true,
  state: {
    //存储公共数据
    countA: 200,
  },  
  mutations: {
    // 定义修改state数据的方法
    incrementA(state) {
      state.countA++;
    },
    decrementA(state) {
      state.countA--;
    },
  },
  actions: {
    // 使用异步的方式来触发mutations中的方法进行提交
    incrementAsyncA({ commit }) {
      // 模拟一个异步操作,例如从 API 获取数据
      setTimeout(() => {
        commit('incrementA');
      }, 1000);
    },
  },
  getters: {
    // 获取状态的方法
    getCountA: (state) => state.countA,
  },
};

4、在main.js中引入store

import Vue from 'vue'
import App from './App.vue'
import store from './store/store';//引入store 

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store,//注册store
}).$mount('#app')

5、在组件中使用

<template>
  <div>
    <h2>Root Module</h2>
    <p>
      Count from Root Module: 
      <!-- 显示方式一:通过计算属性获取getter -->
      {{ rootCount }} || 
      <!-- 显示方式二:直接获取state中的值 -->
      {{ $store.state.count }} || 
      <!-- 显示方式三:通过...mapState(['count'])直接使用count -->
      {{ count }}
    </p>
    <button @click="incrementRoot">增加模块 A 计数</button>
    <button @click="decrementRoot">减少模块 A 计数</button>

    <h2>Module A</h2>
    <p>
      Count from Module A: 
      <!-- 显示方式一:通过计算属性获取getter,需要配置namespaced -->
      {{ moduleACount }} || 
      <!-- 显示方式二:通过在store中注册的模块直接使用modulesA的值 -->
      {{ $store.state.a.countA }}
    </p>
    <button @click="incrementModuleA">增加模块 A 计数</button>
    <button @click="decrementModuleA">减少模块 A 计数</button>

    <button @click="incrementModuleAAsync">异步增加模块 A 计数</button>
  </div>
</template>

<script>
import { mapState,mapMutations,mapActions } from 'vuex';

export default {
  computed: {
    // 1、使用mapState方式获取数据
    // mapState使用方式一
    ...mapState(['count']),
    // mapState使用方式二
    ...mapState({
      rootCountMapState: 'count', // 将根模块的 'getCount' 映射为 'rootCount'
      moduleACount: 'a/getCountA', // 将模块 'a' 的 'getCountA' 映射为 'moduleACount'
    }),
    // 2、使用 mapGetters 辅助函数将模块中的 getters 映射到组件的计算属性    
    rootCount() {
      return this.$store.getters.getCount;
    },
    moduleACount() {
      return this.$store.getters['a/getCountA'];
    },
  },
  methods: {
    // 1、使用mapMutations获取mutations模块方式一
    ...mapMutations({
      incrementRoot: 'increment', // 将根模块的 'increment' 映射为 'incrementRoot'
      decrementRoot: 'decrement', // 将根模块的 'decrement' 映射为 'decrementRoot'
      incrementModuleA: 'a/incrementA', // 将模块 'a' 的 'incrementA' 映射为 'incrementModuleA'
      decrementModuleA: 'a/decrementA', // 将模块 'a' 的 'decrementA' 映射为 'decrementModuleA'
    }),
    ...mapActions({
      incrementModuleAAsync: 'a/incrementAsyncA', // 将 'a/incrementAsyncA' 映射为 'incrementModuleAAsync'
    }),
    // 使用 mapMutations 辅助函数将模块中的 mutations 映射到组件的方法二
    incrementRoot() {
      this.$store.commit('increment');
    },
    decrementRoot() {
      this.$store.commit('decrement');
    },
    incrementModuleA() {
      this.$store.commit('a/incrementA');
    },
    decrementModuleA() {
      this.$store.commit('a/decrementA');
    },
  },
};
</script>

示例效果图:
在这里插入图片描述

vue3状态管理Pinia

  • State(状态): 在 Store 中定义的数据,即应用程序的状态。状态可以是基本类型、对象、数组等。
  • Actions(操作): 在 Store 中定义的用于操作状态的函数。Actions 可以是同步或异步的,通过 this,你可以直接修改状态。如果 actions 返回一个 Promise,Pinia 将等待 Promise 完成,然后再继续执行其他代码。
  • Getter(获取器):获取器允许你从状态中派生出一些衍生数据,类似于计算属性。通过 getters,你可以在不直接修改状态的情况下获取和处理状态的数据。

1、创建项目(参见上面vue2,输入命令后选择vue3即可)
2、安装pinia

npm install pinia
yarn add pinia

3、在main.js中引入

import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia';

const app = createApp(App);

app.use(createPinia());
app.mount('#app')

4、在src下创建store/index.js

import { defineStore } from 'pinia';

export const useExampleStore = defineStore('example', {
  state: () => ({
    counter: 100,
  }),
  actions: {
    increment() {   
      this.counter++;
      console.log(this.counter);
    },
    decrement() {
      this.counter--;
    },
  },
});

5、在组件中通过setup()使用,下面列举了五种改变state数据的方式。

<!-- src/components/ExampleComponent.vue -->
<template>
  <div>
    <p>Counter: {{ exampleStore.counter }}</p>
    <button @click="increment">Increment</button>
    <button @click="decrement">Decrement</button>
  </div>
</template>

<script setup>
import { useExampleStore } from '../store/index';

// 组合式
const exampleStore = useExampleStore();

const increment=()=>{
  // 方式一:在store的action中操作
  exampleStore.increment();
  // 方式二:直接在应用的组件中改变
  // exampleStore.counter++;
  // 方式三:使用$patch整体覆盖
  // exampleStore.$patch({
  //   counter:105
  // })
  // 方式四:使用$patch改变
  // exampleStore.$patch((state)=>{
  //   if(state.counter){
  //     state.counter++;
  //   }
  // })
  // 方式五:使用$state覆盖
  // exampleStore.$state ={
  //   counter:122
  // }
}
const decrement=()=>{
  // exampleStore.decrement();
  exampleStore.counter--;
}

// 选项式
// export default {
//   setup() {
//     const exampleStore = useExampleStore();
//     return {
//       exampleStore,
//       increment: exampleStore.increment,
//       decrement: exampleStore.decrement,
//     };
//   }
// };
</script>

示例效果图:
在这里插入图片描述
Pinia与VueX区别:

  • Vuex 为vue2打造的,Pinia为vue3打造的
  • Pinia没有mutations,直接通过actions进行同步和异步操作,异步需要返回一个promise
  • Pinia 没有modules,设计更为分散,每个组件可以拥有自己的 Store。
  • Vuex 组件通过 mapState、mapMutations、mapActions 等辅助函数来访问存储库中的数据和操作。pinia通过setup 函数来引入和使用 Store,并通过 Store 的实例访问状态和操作。
  • Vuex 对 TypeScript 有良好的支持,但类型推断可能有时候会感觉有点繁琐。Pinia 是使用 TypeScript 编写的,提供了更好的 TypeScript 支持,可以更轻松地推断和利用类型信息。
  • vuex做数据持久化使用插件vuex-persistedstate,Pinia做数据持久化使用pinia-plugin-persist

react状态管理Redux

  • Provider:把父组件传递进来的store对象放入react 上下文中,这样connect组件就可以从上下文中获取到store对象
  • combineReducer:store.state进行分片管理,每个reducer管理state中的一部分。由于createStore只接受一个reducer,所以采用该方法生成一个最终的reducer
  • 中间件(Middleware):中间件是一个位于动作派发和 Reducer 之间的拦截层。它允许你在动作被派发到 Reducer 之前执行额外的逻辑。
  • State:整个 Redux 应用程序的状态,它是只读的。状态的更新是通过触发动作来创建新的状态,而不是直接修改原有状态。
  • action:更新state的状态时用。
  • dispatch:触发store修改state的命令,是createStore返回对象的一个方法
  • connect:从react上下文中取出store对象,订阅store.state的变化,当store state变化时调用自身的方法重新生成connect组件的state,被包装组件便会被重新渲染。不会感知到store的存在,dispatch在这里也是非必须的。
    connect的4个内置组件: 状态mapStateToProps、动作mapDispatchToProps、属性合并mergeProps 和 配置项options
  • 异步中间件:redux没有直接提供执行异步操作的方法,需要手动集成中间件,最常用异步实现的中间件有redux-thunkredux-saga

1、搭建react+ts项目

npm install -g create-react-app
npx create-react-app my-react-ts-app --template typescript

2、安装redux

npm install redux react-redux

3、在src下创建如下结构
src/
– – store/
– – – – index.ts
– – – – reducers/
– – – – – – index.ts
– – – – – – counterReducer.ts

// src/store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducers';

const store = configureStore({
  reducer: rootReducer
});

export default store;

// src/store/reducers/index.ts
// combineReducers 用于将多个 reducer 组合成一个根 reducer
import { combineReducers } from 'redux';
import counterReducer from './counterReducer';

const rootReducer = combineReducers({
  counter: counterReducer,
  // 添加其他 reducer...
});

export default rootReducer;

// src/store/reducers/counterReducer.ts

// 从Redux中导入Action类型,用于定义动作对象
import { Action } from 'redux';

// 定义动作类型的常量,以避免拼写错误
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

// Action Creators: 返回动作对象的函数
export const increment = (): Action => ({ type: INCREMENT });
export const decrement = (): Action => ({ type: DECREMENT });

// Reducer函数:根据派发的动作更新状态
const counterReducer = (state = 0, action: Action): number => {
  switch (action.type) {
    case INCREMENT:
      // 当派发INCREMENT动作时,将当前状态加1
      return state + 1;
    case DECREMENT:
      // 当派发DECREMENT动作时,将当前状态减1
      return state - 1;
    case 'INCREMENTFIXED':
      return state + 5;
    default:
      // 如果动作类型不被识别,则返回当前状态
      return state;
  }
};

// 将counterReducer作为模块的默认导出
export default counterReducer;

4、在index.tsx中引入

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
//引入redux
import { Provider } from 'react-redux';
import store from './store';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>

);

reportWebVitals();

5、在components中创建Counter.tsx

// src/components/Counter.tsx
import React from 'react';
import { connect } from 'react-redux';
import { increment, decrement } from '../store/reducers/counterReducer';

interface CounterProps {
  count: number;
  increment: () => void;
  decrement: () => void;
}

const Counter: React.FC<CounterProps> = ({ count, increment, decrement }) => {
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

// 中间件mapStateToProps 函数将 Redux store 的状态映射到组件的属性。
const mapStateToProps = (state: { counter: number }) => ({
  count: state.counter,
});

// 中间件mapDispatchToProps 对象将动作创建函数映射到组件的属性。
const mapDispatchToProps = {
  increment,
  decrement
};

// connect 函数将组件连接到 Redux store,并将 mapStateToProps 和 mapDispatchToProps 的结果传递给组件
export default connect(mapStateToProps, mapDispatchToProps)(Counter);

示例效果图:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1404152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式日志

1 日志管理 1.1 日志管理方案 服务器数量较少时 直接登录到目标服务器捞日志查看 → 通过 rsyslog 或shell/python 等脚本实现日志搜集并集中保存到统一的日志服务器 服务器数量较多时 ELK 大型的日志系统&#xff0c;实现日志收集、日志存储、日志检索和分析 容器环境 …

基于SpringBoot Vue汽车租赁系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

【代码随想录】刷题笔记Day54

前言 差单调栈就结束代码随想录一刷啦&#xff0c;回家二刷打算改用python补充进博客&#xff0c;小涛加油&#xff01;&#xff01;&#xff01; 647. 回文子串 - 力扣&#xff08;LeetCode&#xff09; 双指针法 中心点外扩&#xff0c;注意中心点可能有一个元素可能有两个…

Android14源码剖析:MediaPlayer与MediaPlayerService区别?(五十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

C#,入门教程(35)——哈希表(Hashtable)的基础知识与用法

上一篇&#xff1a; C#&#xff0c;入门教程(34)——关于函数的参数之引用&#xff08;ref&#xff09;的一点知识与源程序https://blog.csdn.net/beijinghorn/article/details/125411351 有一段故事&#xff1a; King Log The frogs in the lake had an easy life doing ex…

神经网络算法与逻辑回归:优势与差异

神经网络算法和逻辑回归都是预测模型中的重要工具&#xff0c;但它们在处理复杂和非线性问题时表现出不同的性能。本文将深入探讨神经网络算法相对于逻辑回归的优势&#xff0c;以及它们在不同场景下的适用性。 一、引言 神经网络算法和逻辑回归都是预测模型中的重要工具&…

C# CefSharp 根据输入日期段自动选择日期

前言 搞这个Demo整整搞几天通宵&#xff0c;爆肝了。后做的效果出来&#xff0c;还是不错的。给小伙伴看看效果图。 2, 遇到的问题 日期之间相差多少个月数。开始时间框点击对应月份要点击多少次&#xff0c;结束时间框点击对应月份要点击多少次Xpath获取问题。找到对应html元…

力扣刷题第七天 分割数组的最大值

给定一个非负整数数组 nums 和一个整数 k &#xff0c;你需要将这个数组分成 k 个非空的连续子数组。 设计一个算法使得这 k 个子数组各自和的最大值最小。 注&#xff1a; 1 < nums.length < 10000 < nums[i] < 1061 < k < min(50, nums.length) 示例一 输入…

cdh6.3.2的hive配udf

背景 大数据平台的租户要使用udf&#xff0c;他们用beeline连接&#xff0c; 意味着要通过hs2&#xff0c;但如果有多个hs2&#xff0c;各个hs2之间不能共享&#xff0c;需要先把文件传到hdfs&#xff0c;然后手动在各hs2上create function。之后就可以永久使用了&#xff0c;…

宠物互联网医院系统

在数字时代&#xff0c;宠物医疗迎来了一场革新&#xff0c;动物互联网医院系统以其先进的技术和智能的特性成为宠物护理的领军者。本文将介绍宠物互联网医院系统的一些关键技术和代码示例&#xff0c;揭示这一科技奇迹的实现原理。 1. 远程医疗服务的实现 远程医疗服务是宠…

<蓝桥杯软件赛>零基础备赛20周--第15周--快速幂+素数

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周。 在QQ群上交流答疑&am…

Spring-配置文件

一、引子 了解完Spring的基本概念后&#xff0c;我们紧接着来了解Spring中的核心文件--Spring配置文件。 二、配置Bean 我们在上一节Spring的基本概念中快速使用了一下Spring&#xff0c;其中我们在配置文件中主要涉及到就是Bean标签的配置&#xff1a;主要的配置字段有id, …

[设计模式Java实现附plantuml源码~创建型] 对象的克隆~原型模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

C++ //练习 2.36 关于下面的代码,请指出每一个变量的类型以及程序结束时它们各自的值。

C Primer&#xff08;第5版&#xff09; 练习 2.36 练习 2.36 关于下面的代码&#xff0c;请指出每一个变量的类型以及程序结束时它们各自的值。 int a 3, b 4; decltype(a) c a; decltype((b)) d a; c; d;环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09;…

基本语法和 package 与 jar

3.基本语法 1.输入输出 // 导入 java.util 包中的 Scanner 类 import java.util.Scanner;// 定义名为 ScannerExample 的公共类 public class ScannerExample {// 主方法&#xff0c;程序的入口点public static void main(String[] args) {// 创建 Scanner 对象&#xff0c;用…

分布式websocket即时通信(IM)系统保证消息可靠性【第八期】

b站上面本期视频版本&#xff0c;观看视频食用更佳&#xff01;点击即可跳转,找不到视频可以直接搜索我 目前叫 呆呆呆呆梦 目前已经写的文章有。并且有对应视频版本。 git项目地址 【IM即时通信系统&#xff08;企聊聊&#xff09;】点击可跳转 sprinboot单体项目升级成sprin…

2017年认证杯SPSSPRO杯数学建模A题(第二阶段)安全的后视镜全过程文档及程序

2017年认证杯SPSSPRO杯数学建模 A题 安全的后视镜 原题再现&#xff1a; 汽车后视镜的视野对行车安全非常重要。一般来说&#xff0c;汽车的后视镜需要有良好的视野范围&#xff0c;以便驾驶员能够全面地了解车后方的道路情况。同时&#xff0c;后视镜也要使图像的畸变尽可能…

【Linux】—— 共享内存

本期我将要带大家学习的是有关进程间通信的另一种方式——共享内存。共享内存是一种用于进程间通信的高效机制&#xff0c;允许多个进程访问和操作同一块内存区域。 目录 &#xff08;一&#xff09;深刻理解共享内存 1.1 概念解释 1.2 共享内存原理 1.3 共享内存数据结构 …

【5G 接口协议】N2接口协议NGAP(NG Application Protocol)介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

web开发学习笔记(13.mybatis基于注解配置)

1.使用mybatis基本步骤 2.引入依赖 <!-- mysql--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency> <!-- mybatis--><dependency><groupId>org…