React 第三十節 使用 useState 和 useEffect Hook實現購物車

不使用 redux 實現 購物車案例

使用 React 自帶的 useState 和 useEffect Hook 即可實現購物車

export default function ShoppingCar() {// 要結算的商品 總數 以及總價const [totalNum, setTotalNum] = useState(0)const [totalPerice, setTotalPerice] = useState(0)// 商品列表 初始化一個mock 數據const [list, setList] = useState(orderLists)...
}

1、新增商品

使用 setList() 進數據狀態更新

// 模擬新增商品
const handleAdd = () => {const curList = [...list]console.log('===curList=', curList)curList.unshift({name: `商品${list.length + 1}`,id: `sss_${list.length + 1}` ,num: 1,price: 12.00,totalPrice: 12.00, })setList([...curList])
}

2、修改商品的數量

const handleChangeNum = (type, id) => {const curList = [...list]if(type === 'ADD') {curList.map(itm => {if (itm.id === id) {itm.num = itm.num + 1itm.totalPrice = itm.num * itm.price}})} else{curList.map(itm => {if (itm.id === id) {itm.num = itm.num !== 0  ? itm.num - 1 : 0itm.totalPrice = itm.num * itm.price}})}setList([...curList])
}

3、選擇要結算的商品

const handleChangeCheckbox = (e, id) =>{console.log('---', e.target.value)const curList = [...list]curList.map(itm => {if (itm.id === id) {itm.isChecked = !itm.isChecked}})setList([...curList])
}

4、計算要結算商品的 總數 及 總價

使用 useEffect() 監測 商品列表的變化

useEffect(() => {let isSelectedLists = []list.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)
}, [list]

5、完整代碼案例

// index.jsx 
import React, {useState, useEffect, useId} from 'react'
import './index.scss'
import { orderLists } from './mock.js'
export default function ShoppingCar() {// const id = useId()const [totalNum, setTotalNum] = useState(0)const [totalPerice, setTotalPerice] = useState(0)const [list, setList] = useState(orderLists)const handleChangeNum = (type, id) => {const curList = [...list]if(type === 'ADD') {curList.map(itm => {if (itm.id === id) {itm.num = itm.num + 1itm.totalPrice = itm.num * itm.price}})} else{curList.map(itm => {if (itm.id === id) {itm.num = itm.num !== 0  ? itm.num - 1 : 0itm.totalPrice = itm.num * itm.price}})}setList([...curList])}const handleChangeCheckbox = (e, id) =>{console.log('---', e.target.value)const curList = [...list]curList.map(itm => {if (itm.id === id) {itm.isChecked = !itm.isChecked}})setList([...curList])}const handleAdd = () => {const curList = [...list]console.log('===curList=', curList)curList.unshift({name: `商品${list.length + 1}`,id: `sss_${list.length + 1}` ,num: 1,price: 12.00,totalPrice: 12.00, })setList([...curList])}useEffect(() => {let isSelectedLists = []list.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)}, [list])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)}>+</span><span className='itm-num'>{itm.num}</span><span  className='handle-icon' onClick={() => handleChangeNum('REDUCE', itm.id)}>-</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>)
}
// index.scss 文件
.li{width: 100%;height: auto;display: flex;align-items: left;justify-content: left;
}
.commodity{width: 100%;height: 46px;display: flex;align-items: center;justify-content: left;&>span{display: inline-block;min-width: 100px;margin-left: 6px;margin-right: 6px;}}
.price{display: inline-block;margin-left: 6px;margin-right: 6px;min-width: 90px;
}
.num{width: 100%;height: 36px;display: flex;align-items: center;cursor: pointer;
}
.handle-icon{display: inline-block;width: 36px;height: 36px;cursor: pointer;line-height: 36px;border: 1px solid #efefef;
}
.itm-num{display: inline-block;padding: 2px 8px;
}
.total{min-width: 100px;color: #ff0000;
}
.total-price{margin-left: 20px;
}
.btn{}

6、注意事項

a、使用useStatesetXXX() 函數進行修改 對象類型時候,需要修改其指針和值如果不修改指向,不會觸發視圖更新
b、列表中每一項需要有唯一性的key,這樣才會觸發唯一性進行數據更新;
c、使用useState 和 useEffect 實現的購物車,只能在當前頁使用,不利于代碼復用,并且會隨著 購物車里面優惠券、折扣等邏輯的增加,而變的難以維護;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/77347.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/77347.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/77347.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

藍橋杯第十一屆省賽C++B組真題解析

藍橋杯第十一屆省賽CB組真題解析 八、回文日期https://www.lanqiao.cn/problems/348/learning 方法一&#xff1a;暴力枚舉所有的日期&#xff0c;記錄有多少個回文日期。 #include <bits/stdc.h> using namespace std; int month[13]{0,31,28,31,30,31,30,31,31,30,31…

Python和MicroPython的解釋器區別

Python和MicroPython的解釋器不是同一個&#xff0c;它們在設計目標、實現方式和運行環境上都有顯著的區別。以下是它們的主要區別&#xff1a; 1. 底層實現 Python解釋器&#xff08;CPython&#xff09;&#xff1a; Python的標準解釋器是CPython&#xff08;C語言實現的Pyt…

Cython加密多層目錄中的Python腳本方案

近期有一個VueJavaDocker項目中需要加密Python腳本的需求&#xff0c;調研后決定采用Cython。 使用Cython編譯為二進制 步驟&#xff1a; 安裝Cython&#xff1a;pip install cython創建setup.py&#xff1a; from distutils.core import setup from Cython.Build import c…

力扣DAY40-45 | 熱100 | 二叉樹:直徑、層次遍歷、有序數組->二叉搜索樹、驗證二叉搜索樹、二叉搜索樹中第K小的元素、右視圖

前言 簡單、中等 √ 好久沒更了&#xff0c;感覺二叉樹來回就那些。有點變懶要警醒&#xff0c;不能止步于笨方法&#xff01;&#xff01; 二叉樹的直徑 我的題解 遍歷每個節點&#xff0c;左節點最大深度右節點最大深度當前節點當前節點為中心的直徑。如果左節點深度更大…

頭歌數據庫【數據庫概論】第10-11章 故障恢復與并發控制

第1關&#xff1a;數據庫恢復技術 1、事務的&#xff08; A&#xff09;特性要求事務必須被視為一個不可分割的最小工作單元 A、原子性 B、一致性 C、隔離性 D、持久性 2、事務的&#xff08;C &#xff09;特性要求一個事務在執行時&#xff0c;不會受到其他事務的影響。 A、原…

windows下,cursor連接MCP服務器

1.下載并安裝node 安裝后&#xff0c;在cmd命令框中&#xff0c;輸入命令node -v可以打印版本號&#xff0c;證明安裝完成 2.下載MCP服務器項目 在MCP服務器找到對應項目&#xff0c;這里以server-sequential-thinking為例子 在本地cmd命令窗口&#xff0c;使用下面命令下載…

前端配置husky,commit-lint導致的git提交錯誤:git xx@0.0.0 lint:lint-staged

前端配置husky&#xff0c;commit-lint導致的git提交錯誤&#xff1a;git xx0.0.0 lint:lint-staged git commit -m "xxx"時出現以下報錯&#xff0c;可能是前端配置husky&#xff0c;commit-lint的原因 //報錯信息 git xx0.0.0 lint:lint-staged首先要知道出現這個錯…

各種場景的ARP攻擊描述筆記(超詳細)

1、ARP報文限速 上一章我們說過ARP報文也是需要上送CPU進行處理的協議報文,如果設備對收到的大量ARP報文全部進行處理,可能導致CPU負荷過重而無法處理其他業務。因此,在處理之前需要對ARP報文進行限速,以保護CPU資源。 1.根據源MAC地址或源IP地址進行ARP限速 當設備檢測到某一…

Django 創建CSV文件

Django使用Python內置的CSV庫來創建動態的CSV&#xff08;逗號分隔值&#xff09;文件。我們可以在項目的視圖文件中使用這個庫。 讓我們來看一個例子&#xff0c;這里我們有一個Django項目&#xff0c;我們正在實現這個功能。創建一個視圖函數 getfile() 。 Django CSV例子 …

HTTPS為何仍有安全漏洞?解析加密協議下的攻擊面

本文深度剖析HTTPS協議在傳輸層、證書體系、配置管理三個維度的安全盲區&#xff0c;揭示SSL/TLS加密掩蓋下的11類攻擊路徑。基于Equifax、SolarWinds等重大事件的技術復盤&#xff0c;提供包含自動化證書巡檢、動態協議升級、加密流量威脅檢測的立體防御方案。 HTTPS不等于絕…

MyBatis 動態 SQL 使用詳解

&#x1f31f; 一、什么是動態 SQL&#xff1f; 動態 SQL 是指根據傳入參數&#xff0c;動態拼接生成 SQL 語句&#xff0c;不需要寫多個 SQL 方法。MyBatis 提供了 <if>、<choose>、<foreach>、<where> 等標簽來實現這類操作 ? 二、動態 SQL 的優點…

樂觀鎖與悲觀鎖的使用場景

悲觀鎖的應用場景 悲觀鎖的基本思想是假設并發沖突會發生&#xff0c;因此在操作數據時會先鎖定數據&#xff0c;直到完成操作并提交事務后才釋放鎖。這種方式適用于寫操作較多、并發沖突可能性較高的場景。 高寫入比例的數據庫操作&#xff1a;如果系統中有很多寫操作&#x…

cpp(c++)win 10編譯GDAL、PROJ、SQLite3、curl、libtiff

cpp&#xff08;c&#xff09;編譯GDAL、PROJ、SQLite3 Sqlite3libtiffcurlprojGDAL Sqlite3 1、下載 Sqlite3 源碼、工具、二進制預編譯 exe Sqlite3 官網&#xff1a;https://www.sqlite.org/download.html 下載 sqlite-amalgamation-3430200.zipsqlite-dll-win64-x64-3430…

【愚公系列】《高效使用DeepSeek》062-圖書庫存管理

??【技術大咖愚公搬代碼:全棧專家的成長之路,你關注的寶藏博主在這里!】?? ??開發者圈持續輸出高質量干貨的"愚公精神"踐行者——全網百萬開發者都在追更的頂級技術博主! ?? 江湖人稱"愚公搬代碼",用七年如一日的精神深耕技術領域,以"…

鏈表算法中常用操作和技巧

目 1.常用技巧 1.1.畫圖 1.2.添加虛擬頭節點 1.3.大膽引入中間變量 1.4.快慢雙指針 1.4.1判斷鏈表是否有環 1.4.2找鏈表中環的入口 ?2.常用操作 2.1. 創建一個新節點 2.2.尾插 2.3.頭插 1.常用技巧 1.1.畫圖 畫圖可以讓一些抽象的文字語言更加形象生動 畫圖&#…

【9】數據結構的串篇章

目錄標題 串的定義順序串的實現初始化賦值打印串求串的長度復制串判斷兩個串長度是否相等連接兩個串比較兩個串內容是否相等插入操作刪除操作調試與代碼合集 串的模式匹配算法樸素的模式匹配算法KMP算法實現模式匹配 串的定義 定義&#xff1a;由0個或多個字符組成的有限序列&…

GMSL Strapping Pins CFG0/CFG1 應用

GMSL device 使用起來還是比較簡單 ADI 已經充分考慮了用戶的需求&#xff0c;盡可能的降低的芯片的使用和配置復雜度 一對加串器和解串器&#xff0c;只要工作模式匹配得當&#xff0c;Link Locked&#xff0c;便能夠正常工作 如果遇到 Link 無法建立&#xff08;Locked&…

`uia.WindowControl` 是什么:獲取窗口文字是基于系統的 UI 自動化接口,而非 OCR 方式

uia.WindowControl 是什么:獲取窗口文字是基于系統的 UI 自動化接口,而非 OCR 方式 uia.WindowControl 通常是基于 Windows 系統的 UI 自動化框架(如 pywinauto 中的 uia 模塊)里用于表示窗口控件的類。在 Windows 操作系統中,每個應用程序的窗口都可以看作是一個控件,ui…

Easysearch VS Opensearch 數據寫入與存儲性能對比

本文記錄 Easysearch 和 Opensearch 數據寫入和數據存儲方面的性能對比。 準備 壓測工具&#xff1a;INFINI Loadgen 對比版本&#xff1a; Easysearch 1.11.1&#xff08;lucene 8.11.4&#xff09;Opensearch 2.19.1&#xff08;lucene 9.12.1&#xff09; 節點 JVM 配置…

力扣題解:142. 環形鏈表 II

在鏈表學習中&#xff0c;我們已經了解了單鏈表和雙鏈表&#xff0c;兩者的最后一個結點都會指向NULL&#xff1b;今天我們介紹的循環列表則不同&#xff0c;其末尾結點指向的這是鏈表中的一個結點。 循環鏈表是一種特殊類型的鏈表&#xff0c;其尾節點的指針指向頭節點&#…