React 购物车案例 使用 react-redux 和 @reduxjs/toolkit 方法

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是react-redux

官网:https://react-redux.js.org

介绍

  • React Redux是Redux的官方React UI 绑定层。它让您的 React 组件从 Redux 存储中读取数据,并将操作分派到存储以更新状态
  • React Redux 由 Redux 团队维护,并与来自 Redux 和 React 的最新 API 保持同步
  • 旨在与 React 的组件模型一起使用。您定义如何从 Redux 中提取组件所需的值,并且组件会根据需要自动更新
  • 提供 API使您的组件能够与 Redux 存储交互,因此您不必自己编写该逻辑
  • 自动实现复杂的性能优化,这样你自己的组件只有在它需要的数据实际发生变化时才会重新
    渲染

为什么要使用react-redux

  • 可以帮助我们订阅store、检查更新数据和触发组件的重新渲染

二、使用步骤

1.引入库

下载 react-redux 和 @reduxjs/toolkit:

npm i react-redux @reduxjs/toolkit
npm i react-router-dom@6
npm i axios

2.创建store

代码如下(示例):

// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import cart from './modules/Cart'
// 1. 创建store
const store = configureStore({

	reducer:cart.reducer

})
export default store

3.创建切片

// store/modules/cart.js //以购物车为例
import { createSlice } from '@reduxjs/toolkit';
const cart = createSlice({
name: 'cart', // 命名空间
initialState: { // 初始化数据的
num: 0,
cart:[]
},
reducers: {
  // 商品加入购物车
    addCart(state, { payload }) {
      // 判断当前商品在购物车中是否存在
      const idx = state.cart.findIndex(item => item.id === payload.id);
      if(idx !== -1) { // 证明当前商品在购物车中存在
        state.cart[idx].num += 1; //数量+1
      } else {
        state.cart.push(payload)
      }
    },
    // 修改购物车中商品的状态
    changeState(state, { payload: id }) { // 将 payload 重命名为id
      // 根据id找下标
      const idx = state.cart.findIndex(item => item.id === id);
      // 更改状态
      state.cart[idx].checked = !state.cart[idx].checked;
    },
    // 全选
    chooseAll(state, { payload:checked }) {
      // 循环购物车中的商品,让每一个商品的状态和全选按钮的状态保持一致
      state.cart.forEach(item => {
        item.checked = checked;
      })
    },
    // 修改商品的数量
     changeNum(state, { payload }) {
      // 根据id找下标
      const idx = state.cart.findIndex(item => item.id === payload.id);

      switch(payload.type) {
        case 'addNum' : // 点击的是加号按钮
          state.cart[idx].num++;
          break;
        case 'descNum' : // 点击的是加号按钮
          state.cart[idx].num > 1 && state.cart[idx].num--;
         break;
        default:
          state.cart[idx].num = payload.num * 1;
      }
    }
}
})
// reduxjs toolkit 把reducer和actions合并在一起了
export const { addCart, changeState, chooseAll, changeNum } = counterSlice.actions;
// 到处reducer
export default cart;

4. 使用 react-redux 中的 Provider 组件包裹整个根组件,传递store

import React from 'react';
import ReactDOM from 'react-dom/client';
//v6路由
import { RouterProvider } from 'react-router-dom'
import router from './router'
//react-redux
import { Provider } from 'react-redux'
import store from './store'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
	<Provider store={ store }>
		<RouterProvider router={ router } />
	</Provider>
</React.StrictMode>
)

5.在 components/list.js 中引入 cart 模块中暴露的方法

import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom';
import axios from 'axios';
import { useDispatch } from 'react-redux'; 
import { addCart } from '../../store/modules/cart';
import "./index.scss"
export default function List() {
  const navigate = useNavigate(); //路由跳转方法
  const [list, setlist] = useState([]);
 
  const dispatch = useDispatch(); // 派发action

  // 封装获取商品列表数据的方法
  const getList = async () => {
    const { data } = await axios.get('/data.json');
    setlist(data);
  }
  
  // 商品加入购物车
  const addGoods = goods => {
    dispatch(addCart({ ...goods, num: 1, checked: false }))
  }

  // 封装渲染商品列表的方法
  const renderList = () => (
    list.map(item => (
      <li key={ item.id }>
        <div className="img-box">
          <img src={'/imgs/' + item.img } alt="" />
        </div>
        <div className="goods-info">
          <div className="goods-title">{ item.title }</div>
          <div className="goods-info-footer">
            <div className="goods-price">{ item.price }</div>
            <div className="add-cart" onClick={ () => addGoods(item) }>加入购物车</div>
          </div>
        </div>
      </li>
    ))
  )

  useEffect(() => {
    getList();
  }, [])

  return (
    <div className="goods-list">
      <div className="goods-list-content">
        <div className="go-cart" onClick={ () => navigate('/cart') }>去购物车</div>
        <ul className="list">{ renderList() }</ul>
      </div>
    </div>
  )
}

cart.js文件(购物车)

import React, { useMemo } from 'react'
import { useNavigate } from 'react-router-dom'
// useSelector:获取数据,useDispatch:派发action
import { useSelector, useDispatch } from 'react-redux';
// 修改商品状态 、全选 、修改数量
import { changeState, chooseAll, changeNum } from '../../store/modules/cart';
export default function Cart() {
  const navigate = useNavigate();
  // 获取到redux中的数据
  const cart = useSelector(store => store.cart);
  const dispatch = useDispatch();
  // 全选按钮的状态
  const checkedAll = useMemo(() => cart.every(item => item.checked));
  // 手动修改购物车中商品的数量
  const updateNum = (id, ev) => {
    if(!isNaN(ev.target.value)) {
      dispatch(changeNum({ type: 'changeNum', id, num: ev.target.value }))
    } else {
      dispatch(changeNum({ type: 'changeNum', id, num: 1 }))
    }
  }
  // 失去焦点的时候触发
  const blur = (id, ev) => {
    ev.target.value == 0 && dispatch(changeNum({ type: 'changeNum', id, num: 1 }))
  }
  // 封装渲染购物车列表的方法
  const renderCart = () => (
    cart.map(item => (
      <li key={ item.id }>
        <div className="checkbox">
          <input type="checkbox" checked={ item.checked } onChange={ () => dispatch(changeState(item.id)) } />
        </div>
        <div className="goods-info">
          <div className="img-box">
            <img src={'/imgs/' + item.img } alt="" />
          </div>
          <div className="goods-introduce">{ item.title }</div>
        </div>
        <div className="goods-price">{ (item.price).toFixed(2) }</div>
        <div className="goods-controler">
          <div className="desc" onClick={() => dispatch(changeNum({ type: 'descNum', id: item.id }))}>-</div>
          <div className="input-wrapper">
            <input type="text" value={ item.num } onChange={ ev => updateNum(item.id, ev) } onBlur={ev => blur(item.id, ev)} />
          </div>
          <div className="add" onClick={() => dispatch(changeNum({ type: 'addNum', id: item.id }))}>+</div>
        </div>
        <div className="goods-total">{ (item.price * item.num).toFixed(2) }</div>
        <div className="del-btn">删除</div>
      </li>
    ))
  )
  return (
    <div className="cart-wrapper">
      <div className="cart-content-wrapper">
        <div className="cart-title">
          <h3>购物车</h3>
          <div className="go-list" onClick={ () => navigate('/list') }>返回商品列表</div>
        </div>
        {
          cart.length ?
          <>
            <div className="cart-list">
              <li>
                <div className="checkbox">
                  <input type="checkbox" />
                </div>
                <div className="goods-info-title">商品信息</div>
                <div className="goods-price-title">单价</div>
                <div className="goods-num-title">商品数量</div>
                <div className="goods-total-title">金额</div>
                <div>操作</div>
              </li>
              { renderCart() }
            </div>
            <div className="footer-wrapper">
              <div className="left-box">
                <label>
                  全选:<input type="checkbox" checked={ checkedAll } onChange={ ev => dispatch(chooseAll(ev.target.checked)) } />
                </label>
                <div className="del-choose-btn">删除</div>
              </div>
              <div className="right-box">
                <div className="choose-goods-total">
                  <span>已选商品</span>
                  <span>0</span></div>
                <div className="total-price">合计:<span>0</span></div>
                <div className="settlement-btn disabled">结算</div>
              </div>
            </div>
          </>
          :
          <div className="empty-cart">, 您还没有选购任何商品<router-link to="/list">赶快去购物吧!</router-link>
          </div>
        }
      </div>
    </div>
  )
}

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值