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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用React的状态来实现全选反选购物车功能。 首先,你需要定义一个组件,例如 `ShoppingCart` 组件,它包含多个 `CartItem` 子组件。每个 `CartItem` 组件都有一个 `checked` 属性,表示该商品是否被选中。 在 `ShoppingCart` 组件中,需要定义一个 `selectedAll` 状态,表示是否全选。同时,还需要定义一个 `handleSelectAll` 函数,用于处理全选/反选功能。该函数将会通过 `onChange` 事件绑定到全选的复选框上。 以下是示例代码: ```jsx import React, { useState } from "react"; const ShoppingCart = ({ items }) => { const [selectedAll, setSelectedAll] = useState(false); // 处理全选/反选 const handleSelectAll = () => { setSelectedAll(!selectedAll); }; // 处理子组件的选中状态改变 const handleItemChange = (index, checked) => { // TODO: 更新 items[index] 的选中状态 }; return ( <div> <label> <input type="checkbox" checked={selectedAll} onChange={handleSelectAll} /> 全选 </label> {items.map((item, index) => ( <CartItem key={index} item={item} checked={item.checked} onChange={handleItemChange} /> ))} </div> ); }; const CartItem = ({ item, checked, onChange }) => { const handleItemChange = (event) => { onChange(item.id, event.target.checked); }; return ( <div> <label> <input type="checkbox" checked={checked} onChange={handleItemChange} /> {item.name} </label> </div> ); }; ``` 在 `ShoppingCart` 组件中,我们通过 `map` 方法遍历所有的商品,并渲染 `CartItem` 子组件。在 `CartItem` 组件中,我们通过 `checked` 和 `onChange` 属性来控制选中状态和处理状态改变。 在 `handleSelectAll` 函数中,我们使用 `setSelectedAll` 来更新 `selectedAll` 状态。在 `handleItemChange` 函数中,我们需要更新 `items` 数组中对应商品的选中状态。你可以通过 `useState` 状态管理库来管理 `items` 数组的状态,或者通过 `Redux` 等状态管理工具来管理状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值