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

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 + 1
            itm.totalPrice = itm.num * itm.price
        }
        })
        
    } else{
        curList.map(itm => {
            if (itm.id === id) {
            itm.num = itm.num !== 0  ? itm.num - 1 : 0
            itm.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) || 0
    const curTotal = isSelectedLists && isSelectedLists.length && isSelectedLists.reduce((total, item) => total + item.totalPrice, 0) || 0
    console.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 + 1
              itm.totalPrice = itm.num * itm.price
            }
          })
            
        } else{
            curList.map(itm => {
              if (itm.id === id) {
                itm.num = itm.num !== 0  ? itm.num - 1 : 0
                itm.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) || 0
     const curTotal = isSelectedLists && isSelectedLists.length && isSelectedLists.reduce((total, item) => total + item.totalPrice, 0) || 0
     console.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 实现的购物车,只能在当前页使用,不利于代码复用,并且会随着 购物车里面优惠券、折扣等逻辑的增加,而变的难以维护;

相关文章:

  • 蓝桥杯真题:英文字母
  • PHP 阿里云oss 使用指南
  • 网络2 IP与MAC IP地址
  • HTML的svg元素
  • jupyter notebook 显示conda虚拟环境
  • LLM生成文本的 束搜索参数是什么(Beam Search)
  • Quarkus 2025终极指南:GraalVM Native Image如何让Java在K8s中起飞?
  • 在 Jupyter Notebook 中使用 Pandas 进行数据操作
  • [实战]多天线空域抗干扰技术:原理、数学推导与工程仿真(完整仿真代码)
  • pytorch 反向传播
  • 力扣刷题DAY11(动态规划-线性DP)
  • 设计模式 --- 状态模式
  • 【软件测试】Postman中如何搭建Mock服务
  • Java流程控制【if分支三种形式】
  • 前端知识点---垃圾回收机制(javascript)
  • mybatis-plus sql改写插件(二)
  • Android:Android Studio右侧Gradle没有assembleRelease等选项
  • 使用js脚本自动生成android项目的app icon图标
  • UML综合实验四
  • 【Linux】进程控制:创建、终止、等待与替换全解析
  • 有哪些营销型网站/百度指数 移民
  • 网站 空间 域名/培训心得体会200字
  • 如何在网站上做社交的链接/关键词在线听
  • 网站做任务赚qb/网络推广的概念
  • 怎样做一个好的网站/市场调研方案
  • 天猫商城官网登录/正规seo关键词排名网络公司