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.pswp.cn/web/75147.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75147.shtml
英文地址,請注明出處:http://en.pswp.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;因此對…