当前位置: 首页 > article >正文

React 之 Redux 第三十一节 useDispatch() 和 useSelector()使用以及详细案例

使用 Redux 实现购物车案例

由于 redux 5.0 已经将 createStore 废弃,我们需要先将 @reduxjs/toolkit 安装一下;

yarn add @reduxjs/toolkit// 或者
npm install @reduxjs/toolkit

使用 vite 创建 React 项目时候 配置路径别名

// 第一种写法
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path';
import { resolve } from 'path'; 
export default defineConfig({plugins: [react()],
...resolve: {alias: {'@': path.resolve(__dirname, './src') // 例如,设置一个别名路径 @ 指向 src 目录}}
...
})
// 第二种写法
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path';
import { resolve } from 'path'; 
const projectRoot = resolve(__dirname); // 获取项目根目录的绝对路径
const srcPath = resolve(projectRoot, 'src'); // 获取 src 目录的绝对路径
export default defineConfig({plugins: [react()],
...resolve: {alias: {'@': srcPath, // 例如,设置一个别名路径 @ 指向 src 目录}}
...
})

1、创建 购物车 store

分别新建
action/carAction.js 文件
reducer/carReducer.js 文件
在这里插入图片描述

1.1、添加action 常量类型

// store/action/carAction.js 文件
// action type 常量
const ADD_CART = 'ADD_CART' // 新增商品
const REMOVE_CART = 'REMOVE_CART' // 删除商品
const ADD_NUM_CART = 'ADD_NUM_CART' // 增加数量
const REDUCE_NUM_CART = 'REDUCE_NUM_CART' // 减少数量
const EDIT_NUM_CART = 'REDUCE_NUM_CART' // 直接修改数量
const CHECKED_CART = 'CHECKED_CART' // 选中要结算的单据

1.2、添加 修改 state 的 action 方法

每个 action 中 必须包含一个 type属性的 常量,返回一个对象,其余参数可以自行定义
抛出需要使用的方法

//  store/action/carAction.js 文件
const addCart = (list, order={name: `商品${list.length + 1}`,id: `sss_${list.length + 1}` ,num: 1,price: 12.00,totalPrice: 12.00, 
}) => ({type: ADD_CART,payload: {order:  order,list: list}
})const removeCart = (id) => ({type: REMOVE_CART,payload: id
})
const addNumCart = (id, num) => ({type: ADD_NUM_CART,payload: {id, num}
})
const reduceNumCart = (id, num) => ({type: REDUCE_NUM_CART,payload: {id, num}
})
const editNumCart = (id, num) => ({type: EDIT_NUM_CART,payload: {id, num}
})
const checkedCart = (id) => ({type: CHECKED_CART,payload: {id}
})export {addCart,removeCart,addNumCart,reduceNumCart,editNumCart,checkedCart
}

1.3、添加 购物车 reducer 方法

自定义的 reducer 中接收两个参数
state: 当前的数据状态
action: 使用dispatch() 触发的 action对象

//  store/reducer/carReducer.js 文件
// 如果有初始值,我们可以这样定义初始值
const initState = {list:[]
}// 购物的 reducer 根据action.type 类型进行业务逻辑处理
const carReducer = (state=initState, action) => {console.log('==carReducer=', state, action)let newLists = []switch (action.type) {case 'ADD_CART':return {list: [action.payload.order, ...state.list]}case 'REMOVE_CART':return {list: state.list.filter(itm => itm.id !== action.payload.id)}case 'ADD_NUM_CART':// 不可以直接修改 state.list 中的数据,这里的数据是只读的state.list.map(itm => {if (itm.id === action.payload.id) {newLists.push({...itm,num: itm.num + 1,totalPrice: (itm.num + 1) * itm.price})} else {newLists.push({...itm})}})return {list: [...newLists]}case 'REDUCE_NUM_CART':state.list.map(itm => {if (itm.id === action.payload.id) {newLists.push({...itm,num: (itm.num > 0 ? itm.num - 1 : 0),totalPrice: (itm.num > 0 ? itm.num - 1 : 0) * itm.price})} else {newLists.push({...itm})}})return {list: [...newLists]}case 'EDIT_NUM_CART':// 直接修改 数量state.list.map(itm => {if (itm.id === action.payload.id) {newLists.push({...itm,num: action.payload.num,totalPrice: action.payload.num * itm.price})} else {newLists.push({...itm})}})return {list: [...newLists]}case 'CHECKED_CART':// 选中state.list.map(itm => {if (itm.id === action.payload.id) {newLists.push({...itm,isChecked: !itm?.isChecked})} else {newLists.push({...itm})}})return {list: [...newLists]}default :return {list: state.list}}
}export {carReducer
}

1.4、抛出 store 实例

当有多个 reducer 时,我们需要使用 combineReducers 将所有reducer 合并

// import { createStore } from 'redux';
// createStore 这种方案 在 5.0中已经弃用
import {  configureStore } from '@reduxjs/toolkit'
import { combineReducers } from 'redux';
import { textReducer } from './reducer'
import { carReducer } from './reducer/carReducer.js'
const rootReducer = combineReducers({textReducer: textReducer,carReducer: carReducer,});
const store = configureStore({reducer: rootReducer
})export default store

2、使用触发 购物车 store 数据更新

2.1、引入需要使用的 Action 方法

import { addCart,removeCart,addNumCart,reduceNumCart,editNumCart,checkedCart
} from '@/store/action/carAction.js'

2.2、获取 useDispatch的dispatch 和 useSelector 中的 reducer

import { useDispatch, useSelector } from 'react-redux'
// useDispatch Hook 触发 action 中方法
const dispatch = useDispatch()
// useSelector 获取最新的 state 中购物车数据
const selector = useSelector(state => {console.log('=---selector-', state)return state.carReducer.list
})

2.3、完整案例代码

import React, {useState, useEffect, useId} from 'react'
import './index.scss'
import { useDispatch, useSelector } from 'react-redux'
import { addCart,removeCart,addNumCart,reduceNumCart,editNumCart,checkedCart
} from '@/store/action/carAction.js'
export default function ShoppingCar() {const dispatch = useDispatch()const selector = useSelector(state => {console.log('=---selector-', state)return state.carReducer.list})const [totalNum, setTotalNum] = useState(0)const [totalPerice, setTotalPerice] = useState(0)const [list, setList] = useState([])const handleChangeNum = (type, id, num) => {if(type === 'ADD') {// 使用 dispatch 调用 action 中的 addNumCart 方法进行累加dispatch(addNumCart(id, num))} else{dispatch(reduceNumCart(id, num))}}const handleChangeCheckbox = (e, id) =>{// 使用 dispatch 调用 action 中的 checkedCart 获取选中 反选操作dispatch(checkedCart(id))}const handleAdd = () => {// 新增商品dispatch(addCart([...selector]))}useEffect(() => {let isSelectedLists = []selector.map(itm => {if (itm.isChecked) {isSelectedLists.push(itm)}})console.log('=isSelectedLists==', isSelectedLists)const curNum = isSelectedLists && isSelectedLists.length &&isSelectedLists.reduce((total, item) => total + item.num, 0) || 0const curTotal = isSelectedLists && isSelectedLists.length && isSelectedLists.reduce((total, item) => total + item.totalPrice, 0) || 0console.log('==curNum==', curNum)console.log('==curTotal==', curTotal)setTotalNum(curNum)setTotalPerice(curTotal)console.log('=000=selector=', selector)setList([...selector])}, [selector])return (<div className='list'>{list.map(itm => {return (<div className="li" key={itm.id}><div className='commodity'><input type="checkbox" name="" id="" value={itm.isChecked} onClick={(e) => handleChangeCheckbox(e, itm.id)}/><span>{itm.name}</span></div><div className="price">单价:{itm.price}</div><div className='num'><span className='handle-icon' onClick={() => handleChangeNum('ADD', itm.id, itm.num)}>+</span><span className='itm-num'>{itm.num}</span><span  className='handle-icon' onClick={() => handleChangeNum('REDUCE', itm.id, itm.num)}>-</span></div><div className='total'>总价:{itm.totalPrice}</div></div>)})}<div className='total'><span className='total-num'>共计:{totalNum}</span><span className='total-price'>合计:{totalPerice}</span></div><button className="btn" onClick={handleAdd}>增加商品</button></div>)
}

3、总结

1、使用 redux 方便在 reducer 中集中式管理业务代码,提升代码的维护性;
2、使用 store 统一管理 购物车的状态,方便代码进行复用,只需要传入对应参数即可;
3、如果是简单的逻辑,使用redux 进行状态管理,会增加代码的负责性,不如 直接使用 React 中自带的 HOOKS 进行实现;
4、多页面共享数据状态,业务逻辑复杂的,使用 redux 更方便一些;

相关文章:

React 之 Redux 第三十一节 useDispatch() 和 useSelector()使用以及详细案例

使用 Redux 实现购物车案例 由于 redux 5.0 已经将 createStore 废弃&#xff0c;我们需要先将 reduxjs/toolkit 安装一下&#xff1b; yarn add reduxjs/toolkit// 或者 npm install reduxjs/toolkit使用 vite 创建 React 项目时候 配置路径别名 &#xff1a; // 第一种写法…...

6.1es新特性解构赋值

解构赋值是 ES6&#xff08;ECMAScript 2015&#xff09;引入的语法&#xff0c;通过模式匹配从数组或对象中提取值并赋值给变量。&#xff1a; 功能实现 数组解构&#xff1a;按位置匹配值&#xff0c;如 let [a, b] [1, 2]。对象解构&#xff1a;按属性名匹配值&#xff0c;…...

4月12日随笔

今天大风天气的第一天&#xff0c;周六&#xff0c;早上九点半起来听了排球技术台培训。结果一天都没顾得上看教学视频。黄老师说有排球基础的可以试试当主裁&#xff0c;那一定要争取一下&#xff01; 上午看了两集小排球&#xff0c;然后开始了解一些中介相关信息。因为下午…...

MCP遇见Web3:从边缘计算到去中心化的无限想象

MCP遇见Web3:从边缘计算到去中心化的无限想象 在数字化转型的浪潮中,边缘计算(MCP,Micro Control Protocol)和Web3技术分别在计算效率与去中心化架构上发挥着各自的优势。当两者融合,会碰撞出哪些火花?作为一名技术极客,我最近开始深度研究MCP与Web3工具的集成,试图探…...

Llama 4全面评测:官方数据亮眼,社区测试显不足之处

引言 2025年4月&#xff0c;Meta正式发布了全新的Llama 4系列模型&#xff0c;这标志着Llama生态系统进入了一个全新的时代。Llama 4不仅是Meta首个原生多模态模型&#xff0c;还采用了混合专家(MoE)架构&#xff0c;并提供了前所未有的上下文长度支持。本文将详细介绍Llama 4…...

【C++】函数直接返回bool值和返回bool变量差异

函数直接返回bool值和返回bool变量差异 背景 在工作中遇到一个比较诡异的问题&#xff0c;场景是给业务方提供的SDK有一个获取状态的函数GetStatus&#xff0c;函数的返回值类型是bool&#xff0c;在测试过程中发现&#xff0c;SDK返回的是false&#xff0c;但是业务方拿到的…...

游戏盾IP可以被破解吗

游戏盾IP&#xff08;如上海云盾SDK、腾讯云游戏盾&#xff09;是专为游戏行业设计的高防服务&#xff0c;旨在抵御DDoS攻击、CC攻击等威胁。其安全性取决于​​技术架构、防护能力​​以及​​运维策略​​。虽然理论上没有绝对“无法破解”的系统&#xff0c;但游戏盾IP在合理…...

第1节:计算机视觉发展简史

计算机视觉与图像分类概述&#xff1a;计算机视觉发展简史 计算机视觉&#xff08;Computer Vision&#xff09;作为人工智能领域的重要分支&#xff0c;是一门研究如何使机器"看"的科学&#xff0c;更具体地说&#xff0c;是指用摄影机和计算机代替人眼对目标进行识…...

ARM内核与寄存器

ARM内核与寄存器详解 目录 ARM架构概述ARM处理器模式 Cortex-M3内核的处理器模式Cortex-A系列处理器模式 ARM寄存器集 通用寄存器程序计数器(PC)链接寄存器(LR)堆栈指针(SP)状态寄存器(CPSR/SPSR) 协处理器寄存器NEON和VFP寄存器寄存器使用规范常见ARM指令与寄存器操作 ARM架…...

Hibernate:让对象与数据库无缝对话的全自动ORM框架

一、为什么需要全自动ORM&#xff1f; 在手动编写SQL的时代&#xff0c;开发者需要在Java代码和数据库表之间来回切换&#xff1a; // Java对象 public class User {private Long id;private String name;// getters and setters }// SQL语句 SELECT * FROM user WHERE id ?…...

TDengine 语言连接器(C/C++)

简介 C/C 开发人员可以使用 TDengine 的客户端驱动&#xff0c;即 C/C 连接器&#xff08;以下都用 TDengine 客户端驱动表示&#xff09;&#xff0c;开发自己的应用来连接 TDengine 集群完成数据存储、查询以及其他功能。TDengine 客户端驱动的 API 类似于 MySQL 的 C API。…...

英伟达Llama-3.1-Nemotron-Ultra-253B-v1语言模型论文快读:FFN Fusion

FFN Fusion: Rethinking Sequential Computation in Large Language Models 代表模型&#xff1a;Llama-3.1-Nemotron-Ultra-253B-v1 1. 摘要 本文介绍了一种名为 FFN Fusion 的架构优化技术&#xff0c;旨在通过识别和利用自然并行化机会来减少大型语言模型&#xff08;LLM…...

云曦月末断网考核复现

Web 先看一个BUUCTF中的文件一个上传题 [BUUCTF] 2020新生赛 Upload 打开后是一个文件上传页面 随便上传一个txt一句话木马后出现js弹窗&#xff0c;提示只能上传图片格式文件 说明有前端验证。我的做法是把一句话改为.jpg格式&#xff0c; 然后上传 访问发现虽然上传成功了…...

Flutter常用组件实践

Flutter常用组件实践 1、MaterialApp 和 Center(组件居中)2、Scaffold3、Container(容器)4、BoxDecoration(装饰器)5、Column(纵向布局)及Icon(图标)6、Column/Row(横向/横向布局)+CloseButton/BackButton/IconButton(简单按钮)7、Expanded和Flexible8、Stack和Po…...

MySQL MVCC 机制详解

MySQL MVCC 机制详解 1. MVCC 基本概念 MVCC 是一种并发控制的方法&#xff0c;主要用于数据库管理系统&#xff0c;允许多个事务同时读取数据库中的同一个数据项&#xff0c;而不需要加锁&#xff0c;从而提高了数据库的并发性能。 ┌──────────────────…...

【面试】封装、继承、多态的具象示例 模板编程的理解与应用场景 链表适用的场景

文章目录 C面试&#xff1a;封装、继承、多态的具象示例1. 封装 (Encapsulation)2. 继承 (Inheritance)3. 多态 (Polymorphism)综合示例&#xff1a;封装、继承、多态 C模板编程的理解与应用场景我对模板编程的理解C中最常用的模板编程场景1. STL (标准模板库)2. 通用容器实现3…...

0.机器学习基础

0.人工智能概述&#xff1a; &#xff08;1&#xff09;必备三要素&#xff1a; 数据算法计算力 CPU、GPU、TPUGPU和CPU对比&#xff1a; GPU主要适合计算密集型任务&#xff1b;CPU主要适合I/O密集型任务&#xff1b; 【笔试问题】什么类型程序适合在GPU上运行&#xff1…...

系统与网络安全------网络通信原理(4)

资料整理于网络资料、书本资料、AI&#xff0c;仅供个人学习参考。 网络层解析 IP 网络层概述 位于OSI模型第三层作用 定义网络设备的逻辑地址&#xff0c;俗称网络层地址&#xff08;如IP地址&#xff09; 在不同的网段之间选择最佳数据转发路径 协议 IP协议 IP数据包…...

Java基础 4.12

1.方法的重载&#xff08;OverLoad&#xff09; 基本介绍 Java中允许同一个类&#xff0c;多个同名方法的存在&#xff0c;但要求形参列表不一致&#xff01; 如 System.out.println(); out是PrintStream类型 重载的好处 减轻了起名的麻烦减轻了记名的麻烦 2.重载的快速入…...

XILINX DDR3专题---(1)IP核时钟框架介绍

1.什么是Reference Clock&#xff0c;这个时钟一定是200MHz吗&#xff1f; 2.为什么APP_DATA是128bit&#xff0c;怎么算出来的&#xff1f; 3.APP &#xff1a;MEM的比值一定是1:4吗&#xff1f; 4.NO BUFFER是什么意思&#xff1f; 5.什么情况下Reference Clock的时钟源可…...

clickhouse注入手法总结

clickhouse 遇到一题clickhouse注入相关的&#xff0c;没有见过&#xff0c;于是来学习clickhouse的使用&#xff0c;并总结相关注入手法。 环境搭建 直接在docker运行 docker pull clickhouse/clickhouse-server docker run -d --name some-clickhouse-server --ulimit n…...

React 组件样式

在这里插入图片描述 分为行内和css文件控制 行内 通过CSS中类名文件控制...

利用 pyecharts 实现地图的数据可视化——第七次人口普查数据的2d、3d展示(关键词:2d 、3d 、map、 geo、涟漪点)

参考文档&#xff1a;链接: link_pyecharts 官方文档 1、map() 传入省份全称&#xff0c;date_pair 是列表套列表 [ [ ],[ ] … ] 2、geo() 传入省份简称&#xff0c;date_pair 是列表套元组 [ ( ),( ) … ] 1、准备数据 population_data&#xff1a;简称经纬度 population_da…...

解决 Elasticsearch 分页查询性能瓶颈——从10分钟到秒级的优化实践

大家好&#xff0c;我是铭毅天下&#xff0c;一名专注于 Elasticsearch &#xff08;以下简称ES&#xff09;技术栈的技术爱好者。 今天我们来聊聊球友提出的一个实际问题&#xff1a; ES分页查询性能很差&#xff0c;使用from/size方式检索居然需要10分钟&#xff01; 这是一个…...

记录IBM服务器检测到备份GPT损坏警告排查解决过程

服务器设备&#xff1a;IBM x3550 M4 Server IMM默认IP地址&#xff1a;192.168.70.125 用户名&#xff1a;USERID 密码&#xff1a;PASSW0RD&#xff08;注意是零0&#xff09; 操作系统&#xff1a;Windows Hyper-V Server 2016 IMM Web System Status Warning&#xff1…...

毫米波测试套装速递!高效赋能5G/6G、新材料及智能超表面(RIS)研发

德思特&#xff08;Tesight&#xff09;作为全球领先的测试测量解决方案提供商&#xff0c;始终致力于为前沿技术研发提供高精度、高效率的测试工具。 针对毫米波技术在高频通信、智能超表面&#xff08;RIS&#xff09;、新材料等领域的快速应用需求&#xff0c;我们推出毫米…...

Linux中卸载宝塔面板

输入命令 wget http://download.bt.cn/install/bt-uninstall.sh 执行脚本命令 sh bt-uninstall.sh 根据自己的情况选择1还是2 卸载完成校验 bt 这样我们的宝塔面板就卸载完了...

无人机的振动与噪声控制技术!

一、振动控制技术要点 1. 振动源分析 气动振动&#xff1a;旋翼桨叶涡脱落&#xff08;如叶尖涡干涉&#xff09;、动态失速&#xff08;Dynamic Stall&#xff09;引发的周期性气动激振力&#xff08;频率与转速相关&#xff09;。 机械振动&#xff1a;电机偏心、传动轴不…...

Linux(CentOS10) gcc编译

本例子摘自《鸟哥的linux私房菜-基础学习第四版》 21.3 用make进行宏编译 书中的代码在本机器(版本见下&#xff09;编译出错&#xff0c;改正代码后发布此文章&#xff1a; #kernel version: rootlocalhost:~/testmake# uname -a Linux localhost 6.12.0-65.el10.x86_64 #1…...

【蓝桥杯】第十六届蓝桥杯 JAVA B组记录

试题 A: 逃离高塔 很简单&#xff0c;签到题&#xff0c;但是需要注意精度&#xff0c;用int会有溢出风险 答案&#xff1a;202 package lanqiao.t1;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWrit…...