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 更方便一些;

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

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

相关文章

Spring Boot 中集成 Knife4j:解决文件上传不显示文件域的问题

Spring Boot 中集成 Knife4j&#xff1a;解决文件上传不显示文件域的问题 在使用 Knife4j 为 Spring Boot 项目生成 API 文档时&#xff0c;开发者可能会遇到文件上传功能不显示文件域的问题。本文将详细介绍如何解决这一问题&#xff0c;并提供完整的解决方案。 Knife4j官网…

OpenCV 图形API(17)计算输入矩阵 src 中每个元素的平方根函数sqrt()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 描述 计算数组元素的平方根。 cv::gapi::sqrt 函数计算每个输入数组元素的平方根。对于多通道数组&#xff0c;每个通道会独立处理。其精度大约与内置的 …

大学论文书写规范与格式说明

大学论文书写规范与格式说明 (适用于人文社科、理工科通用框架) 一、论文整体结构 1. 基本组成部分 封面 包含论文标题、作者姓名、学院/专业、学号、指导教师、提交日期等(按学校模板填写)。 中英文摘要 中文摘要:300~500字,概述研究背景、方法、结论与创新点,末尾附…

C# 串口通信

1. 导入 using System.IO.Ports;2. 初始化定义 SerialPort sp new SerialPort(); // 设置串口 sp.PortName "COM3"; // 串口 sp.BaudRate 9600; // 波特率 sp.Parity Parity.None; // 校验位 sp.DataBits 8; // 数据位 sp.StopBits StopBits.One; // 停…

android14 keycode 上报 0 解决办法

驱动改完后发现上报了keycode=0 04-07 13:02:33.201 2323 2662 D WindowManager: interceptKeyTq keycode=0 interactive=false keyguardActive=true policyFlags=2000000 04-07 13:02:33.458 2323 2662 D WindowManager: interceptKeyTq keycode=0 interactive=false key…

C++day9

思维导图 牛客练习 练习&#xff1a; 将我们写的 myList 迭代器里面 operator[] 和 operator 配合异常再写一遍 #include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector>…

批量合并多张 jpg/png 图片为长图或者 PDF 文件,支持按文件夹合并图片

我们经常会碰到需要将多张图片拼成一张图片的场景&#xff0c;比如将多张图片拼成九宫格图片&#xff0c;或者将多张图片拼成一张长图。还有可能会碰到需要将多张图片合并成一个完整的 PDF 文件来方便我们进行打印或者传输等操作。那这些将图片合并成一张图片或者一个完整的文档…

程序化广告行业(73/89):买卖双方需求痛点及应对策略深度剖析

程序化广告行业&#xff08;73/89&#xff09;&#xff1a;买卖双方需求痛点及应对策略深度剖析 大家好&#xff01;一直以来&#xff0c;我都热衷于在技术领域探索学习&#xff0c;也深知知识的分享能让我们共同进步。写这篇博客的目的&#xff0c;就是希望能和大家一起深入了…

[随笔] nn.Embedding的前向传播与反向传播

nn.Embedding的前向传播与反向传播 nn.Embedding的前向计算过程 embedding module 的前向过程其实是一个索引&#xff08;查表&#xff09;的过程 表的形式是一个 matrix&#xff08;embedding.weight, learnable parameters&#xff09; matrix.shape: (v, h) v&#xff1a;…

构建实时、融合的湖仓一体数据分析平台:基于 Delta Lake 与 Apache Iceberg

1. 执行摘要 挑战&#xff1a; 传统数据仓库在处理现代数据需求时面临诸多限制&#xff0c;包括高昂的存储和计算成本、处理海量多样化数据的能力不足、以及数据从产生到可供分析的端到端延迟过高。同时&#xff0c;虽然数据湖提供了低成本、灵活的存储&#xff0c;但往往缺乏…

Maven error:Could not transfer artifact

问题描述 当项目从私有仓库下载依赖时&#xff0c;Maven 报错&#xff0c;无法从远程仓库下载指定的依赖包&#xff0c;错误信息如下&#xff1a; Could not transfer artifact com.ding.abcd:zabk-java:pom from/to releases (http://192.1122.101/repory/mavenleases/): 此…

Dify 生成提示词的 Prompt

Dify 生成提示词的 Prompt **第1次提示词****第2次提示词****第3次提示词**总结 Dify 生成提示词是&#xff0c;会和LLM进行3次交互&#xff0c;下面是和LLM进行交互是的Prompt。 以下是每次提示词的概要、目标总结以及原始Prompt&#xff1a; 第1次提示词 概要&#xff1a; …

sqli-labs靶场 less4

文章目录 sqli-labs靶场less 4 联合注入 sqli-labs靶场 每道题都从以下模板讲解&#xff0c;并且每个步骤都有图片&#xff0c;清晰明了&#xff0c;便于复盘。 sql注入的基本步骤 注入点注入类型 字符型&#xff1a;判断闭合方式 &#xff08;‘、"、’、“”&#xf…

【什么是动态链接?这里的动态是什么意思?链接了什么?】

动态链接&#xff08;Dynamic Linking&#xff09;详解 1. 什么是动态链接&#xff1f; 动态链接是 Java 虚拟机&#xff08;JVM&#xff09;在运行时将字节码中的符号引用&#xff08;Symbolic Reference&#xff09;转换为直接引用&#xff08;Direct Reference&#xff09;…

AWS S3深度剖析:云存储的瑞士军刀

1. 引言 在当今数据驱动的世界中,高效、可靠、安全的数据存储解决方案至关重要。Amazon Simple Storage Service (S3)作为AWS生态系统中的核心服务之一,为企业和开发者提供了一个强大而灵活的对象存储平台。本文将全面解析S3的核心特性,帮助读者深入理解如何充分利用这一&q…

【Game】Powerful——Martial Arts Challenge(6)

文章目录 攻略关卡一&#xff08;虎子&#xff09;关卡二关卡三关卡四关卡五关卡六——奇穷 攻略 关卡一&#xff08;虎子&#xff09; 参战选手 出手顺序 关卡二 参战选手 出手顺序 关卡三 参战选手 出手顺序 关卡四 参战选手 出手顺序 关卡五 参战选手 出手顺序 关卡六…

PPIO × UI-TARS:用自然语言操控电脑,AI Agent 的极致体验

Manus的爆火预示着AI 正在从单纯的文本生成和图像识别迈向更复杂的交互场景。字节跳动近期推出的开源项目 UI-TARS Desktop 为我们展示了一种全新的可能性&#xff1a;能够通过自然语言理解和处理来控制计算机界面。这款工具代表了人工智能与人机交互领域的重大突破&#xff0c…

电脑屏保壁纸怎么设置 桌面壁纸设置方法详解

电脑桌面壁纸作为我们每天面对的第一视觉元素&#xff0c;不仅能够彰显个人品味&#xff0c;还能营造舒适的工作或娱乐氛围。电脑桌面壁纸怎么设置呢&#xff1f;下面本文将为大家介绍Windows和macOS两大主流操作系统中设置电脑桌面壁纸的方法&#xff0c;帮助大家快速设置个性…

popupwindow拦截返回点击

目的&#xff1a;弹窗只有点击按钮可以关闭。 前提&#xff1a;弹窗内有输入框 试了网上的一些方法 设置弹窗焦点 setFocusable(false) &#xff08;会导致软键盘无法显示&#xff09;重写 onBackPressed 方法 &#xff08;不会走这里&#xff09;为 popupwindow 设置 onKey…

数学知识——矩阵乘法

使用矩阵快速幂优化递推问题 对于一个递推问题&#xff0c;如递推式的每一项系数都为常数&#xff0c;我们可以使用矩阵快速幂来对算法进行优化。 一般形式为&#xff1a; F n F 1 A n − 1 F_nF_1A^{n-1} Fn​F1​An−1 由于递推式的每一项系数都为常数&#xff0c;因此对…