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

react购物车Redux

入口index.js

import React from 'react'
import {createRoot} from 'react-dom/client'

import App from './App'
//注入store
import {Provider} from "react-redux";
import store from "./store";

const root = createRoot(document.getElementById('root'))
root.render(
    <Provider store={store}>
        <App/>
    </Provider>
)

srotre/modules/takeway.js

//编写store
import {createSlice} from "@reduxjs/toolkit";
import axios from "axios";

const foodsStore = createSlice({
    name: 'foods',
    initialState: {
        //商品列表
        foodsList: [],
        //菜单激活的下标值
        activeIndex: 0,
        // 购物车列表
        cartList: []
    },
    reducers: {
        // 更改商品列表
        setFoodsList(state, action) {
            state.foodsList = action.payload
        },
        // 更改activeIndex
        changActiveIndex(state, action) {
            state.activeIndex = action.payload
        },
        //添加购物车
        addCart(state, action) {
            //是否添加过  如果添加只更新count 没有添加过 直接push进去
            const data = JSON.parse(JSON.stringify(state.cartList))
            const item = data
                .find(item => item.id === action.payload.id)
            const index = data.findIndex(item => item.id === action.payload.id)
            console.log(item)
            if (item) {
                state.cartList[index].count++
            } else {
                state.cartList.push(action.payload)
            }

        },
        //count增加
        addCount(state, action) {
            const data = JSON.parse(JSON.stringify(state.cartList))
            const item = data
                .find(item => item.id === action.payload.id)
            const index = data.findIndex(item => item.id === action.payload.id)
            state.cartList[index].count++

        },
        //count--
        decreCount(state, action) {
            const data = JSON.parse(JSON.stringify(state.cartList))
            const item = data.find(item => item.id === action.payload.id)
            const index = data.findIndex(item => item.id === action.payload.id)
            if (state.cartList[index].count === 0) {
                return
            }
            state.cartList[index].count--

        },
        // 清除购物车
        clearCart (state) {
            state.cartList = []
        }
    }
})
//异步获取部分 结构出创建action对象
const { setFoodsList, changActiveIndex, addCart, addCount, decreCount, clearCart } = foodsStore.actions
console.log(foodsStore.actions, 11111111111)
const fetchChannelList = () => {
    console.log('123')
    return async (dispatch) => {
        console.log('编写异步逻辑')
        // 编写异步逻辑
        const res = await axios.get('http://localhost:3004/takeaway')
        // 调用dispatch函数提交action
        dispatch(setFoodsList(res.data))
    }
}
export { fetchChannelList, changActiveIndex, addCart, addCount, decreCount, clearCart }
//获取reducer函数
const reducer = foodsStore.reducer

export default reducer

srotre/modules/index.js

import foodsReducer from './modules/takeaway'
import { configureStore } from '@reduxjs/toolkit'

const store = configureStore({
    reducer: {
        foods: foodsReducer
    }
})

export default store

Menus/index.js

import classNames from 'classnames'
import './index.scss'
import {useDispatch, useSelector} from "react-redux";
import {changActiveIndex} from "../../store/modules/takeaway";

const Menu = () => {
    // const foodsList = [
    //   {
    //     "tag": "318569657",
    //     "name": "一人套餐",
    //     "foods": [
    //       {
    //         "id": 8078956697,
    //         "name": "烤羊肉串(10串)",
    //         "like_ratio_desc": "好评度100%",
    //         "month_saled": 40,
    //         "unit": "10串",
    //         "food_tag_list": ["点评网友推荐"],
    //         "price": 90,
    //         "picture": "https://zqran.gitee.io/images/waimai/8078956697.jpg",
    //         "description": "",
    //         "tag": "318569657"
    //       },
    //       {
    //         "id": 7384994864,
    //         "name": "腊味煲仔饭",
    //         "like_ratio_desc": "好评度81%",
    //         "month_saled": 100,
    //         "unit": "1人份",
    //         "food_tag_list": [],
    //         "price": 39,
    //         "picture": "https://zqran.gitee.io/images/waimai/7384994864.jpg",
    //         "description": "",
    //         "tag": "318569657"
    //       },
    //       {
    //         "id": 2305772036,
    //         "name": "鸡腿胡萝卜焖饭",
    //         "like_ratio_desc": "好评度91%",
    //         "month_saled": 300,
    //         "unit": "1人份",
    //         "food_tag_list": [],
    //         "price": 34.32,
    //         "picture": "https://zqran.gitee.io/images/waimai/2305772036.jpg",
    //         "description": "主料:大米、鸡腿、菜心、胡萝卜",
    //         "tag": "318569657"
    //       },
    //       {
    //         "id": 2233861812,
    //         "name": "小份酸汤莜面鱼鱼+肉夹馍套餐",
    //         "like_ratio_desc": "好评度73%",
    //         "month_saled": 600,
    //         "unit": "1人份",
    //         "food_tag_list": ["“口味好,包装很好~点赞”"],
    //         "price": 34.32,
    //         "picture": "https://zqran.gitee.io/images/waimai/2233861812.jpg",
    //         "description": "酸汤莜面鱼鱼,主料:酸汤、莜面 肉夹馍,主料:白皮饼、猪肉",
    //         "tag": "318569657"
    //       }
    //     ]
    //   }
    // ]
    const {foodsList, activeIndex} = useSelector(state => state.foods)
    const menus = foodsList.map(item => ({tag: item.tag, name: item.name}))
    const dispath = useDispatch()
    return (
        <nav className="list-menu">
            {/* 添加active类名会变成激活状态 */}
            {menus.map((item, index) => {
                return (
                    <div
                        onClick={() => dispath(changActiveIndex(index))}
                        key={item.tag}
                        className={classNames(
                            'list-menu-item',
                            activeIndex === index && 'active'
                        )}
                    >
                        {item.name}
                    </div>
                )
            })}
        </nav>
    )
}

export default Menu

FoodsItem.js

import './index.scss'
import { useDispatch } from 'react-redux'
import {addCart} from "../../../store/modules/takeaway";
const Foods = ({
  id,
  picture,
  name,
  unit,
  description,
  food_tag_list,
  month_saled,
  like_ratio_desc,
  price,
  tag,
  count
}) => {
  const dispatch = useDispatch()
  return (
    <dd className="cate-goods">
      <div className="goods-img-wrap">
        <img src={picture} alt="" className="goods-img" />
      </div>
      <div className="goods-info">
        <div className="goods-desc">
          <div className="goods-title">{name}</div>
          <div className="goods-detail">
            <div className="goods-unit">{unit}</div>
            <div className="goods-detail-text">{description}</div>
          </div>
          <div className="goods-tag">{food_tag_list.join(' ')}</div>
          <div className="goods-sales-volume">
            <span className="goods-num">月售{month_saled}</span>
            <span className="goods-num">{like_ratio_desc}</span>
          </div>
        </div>
        <div className="goods-price-count">
          <div className="goods-price">
            <span className="goods-price-unit">¥</span>
            {price}
          </div>
          <div className="goods-count">
            <span className="plus" onClick={() => dispatch(addCart({
              id,
              picture,
              name,
              unit,
              description,
              food_tag_list,
              month_saled,
              like_ratio_desc,
              price,
              tag,
              count
            }))}>+</span>
          </div>
        </div>
      </div>
    </dd>
  )
}

export default Foods

Cart.js

import classNames from 'classnames'
import Count from '../Count'
import './index.scss'
import {useDispatch, useSelector} from "react-redux";
import {addCount, clearCart, decreCount} from "../../store/modules/takeaway";
import {useState} from "react";

const Cart = () => {
    const {cartList} = useSelector(state => state.foods)
    const totalPrice = cartList.reduce((a, c) => a + c.price * c.count, 0)
    const totalCount = cartList.reduce((a, c) => a + c.count, 0)
    const dispatch = useDispatch()
    //控制购物车打开关闭的状态
    const [visible, setVisible] = useState(false)
    const onshow = () => {
        if (cartList.length > 0) {
            setVisible(true)
        }
    }
    // const cart = []
    return (
        <div className="cartContainer">
            {/* 遮罩层 添加visible类名可以显示出来 */}
            <div onClick={() => setVisible(false)}
                 className={classNames('cartOverlay', visible && 'visible')}
            />
            <div className="cart">
                {/* fill 添加fill类名可以切换购物车状态*/}
                {/* 购物车数量 */}
                <div onClick={onshow} className={classNames('icon')}>
                    {cartList.length && <div className="cartCornerMark">{totalCount}</div>}
                </div>
                {/* 购物车价格 */}
                <div className="main">
                    <div className="price">
            <span className="payableAmount">
              <span className="payableAmountUnit">¥</span>
                {totalPrice.toFixed(2)}
            </span>
                    </div>
                    <span className="text">预估另需配送费 ¥5</span>
                </div>
                {/* 结算 or 起送 */}
                {/* 结算 or 起送 */}
                {cartList.length > 0 ? (
                    <div className="goToPreview">去结算</div>
                ) : (
                    <div className="minFee">1元起送</div>
                )}
            </div>
            {/* 添加visible类名 div会显示出来 */}
            <div className={classNames('cartPanel', visible && 'visible')}>
                <div className="header">
                    <span className="text">购物车</span>
                    <span className="clearCart" onClick={() => dispatch(clearCart())}>
            清空购物车
          </span>
                </div>

                {/* 购物车列表 */}
                <div className="scrollArea">
                    {cartList.map(item => {
                        return (
                            <div className="cartItem" key={item.id}>
                                <img className="shopPic" src={item.picture} alt=""/>
                                <div className="main">
                                    <div className="skuInfo">
                                        <div className="name">{item.name}</div>
                                    </div>
                                    <div className="payableAmount">
                                        <span className="yuan">¥</span>
                                        <span className="price">{item.price}</span>
                                    </div>
                                </div>
                                <div className="skuBtnWrapper btnGroup">
                                    <Count
                                        count={item.count}
                                        onPlus={() => dispatch(addCount({id: item.id}))}
                                        onMinus={() => dispatch(decreCount({id: item.id}))}
                                    />
                                </div>
                            </div>
                        )
                    })}
                </div>
            </div>
        </div>
    )
}

export default Cart


http://www.kler.cn/a/291330.html

相关文章:

  • 提升汽车金融租赁系统的效率与风险管理策略探讨
  • Android中创建ViewModel的几种方法
  • 数据插入操作的深度分析:INSERT 语句使用及实践
  • 科研绘图系列:R语言科研绘图之标记热图(heatmap)
  • Rabbitmq 具体怎么做到削峰的,是丢弃部分消费吗,有的实际场景是不允许丢弃
  • 你已经分清JAVA中JVM、JDK与JRE的作用和关系了吗?
  • 交叉编译概念
  • 秒杀商品实时热点发现及如何进行测试
  • sqlite3 db.configure方法详解:设置项与默认值
  • [STM32]从零开始的STM32标准库环境搭建(小白向)
  • Java项目服务器CPU飙升问题排查
  • 1998-2023年上市公司金融/信贷/资本资源错配程度数据(含原始数据+计算代码+结果)
  • 每日OJ_牛客_Emacs计算器(逆波兰表达式)
  • 图论(1)
  • Day11_0.1基础学习MATLAB学习小技巧总结(11)——程序流程控制2
  • 50ETF期权和股指期权有什么区别?ETF期权应该怎么做?
  • 2018CCPC网络赛 C - Dream
  • windows上的MySql的安装与配置
  • C语言:刷题笔记
  • 鸿蒙界面开发——组件(3):视频组件video
  • 能源交通行业ITSM案例分析报告
  • python学习14:如何读取yaml文件?
  • 跟我一起写 SIPp XML scenario file
  • 【区块链 + 人才服务】教育区域初中综合素质评价系统 | FISCO BCOS应用案例
  • 使用python对股票市场进行数据挖掘的书籍资料有哪些
  • Prometheus+Grafana普罗米修斯,搭建和使用