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

React-Redux总结含购物车案例

React-Redux总结含购物车案例

reduc简介

redux是react全家桶的一员,它为react给i共可预测化的状态管理机制。redux是将整个应用状态存储到一个地方,成为store,里面存放着一颗树状态(state,tree),组件可以派发dispatch行为action给store,而不是直接通知其他组件,其他组件可以通过订阅store中的状态state来刷新自己的视图。

主要的四个特征:

  • 可预测:reducer是纯函数,所有状态是可预测的。
  • 易调试:全局只有一个store。
  • 灵活性:action,修改state。
  • 中心化:middleware机制,源码简介,扩展生态丰富。

设计思想

redux是一种状态管理库,用于管理React应用中的全局状态,核心思想是将应用的状态集中存储在一个全局的Store中,使得状态的变化可追溯,可控制,可预测。

  • 单一的数据源:redux倡导使用单一的数据源的方式来管理应用的状态,即整个应用的状态存储再一个全局的JavaScript对象中,这有助于简单化状态管理的逻辑,使得状态的变化是可预测易于调试的。
  • 不可变性:redux状态是不可变的,即状态一旦创建就不可以修改,每次状态发生变化时,都会生成一个新的状态对象,而不是直接修改原有的状态。这有助于避免状态的不一致和难以追溯的bug。

什么情况下使用redux

  • 某个组件的状态,需要让其他组件可以随时拿到(共享)。
  • 一个组件需要改变另一个组件的状态(通信)。
  • 总体原则是能不用就不用,如果不用比较吃力考虑使用。

redux工作流程

component --> dispatch(action) --> reducer --> subscribe --> getState --> component
  • 1.触发Action:应用中的某个事件或用户行为触发一个Action,Action是一个包含type属性和可选的payload属性通过JavaScript对象,用于描述状态的变化。
  • 2.派发Action:通过调用Redux的dispatch(action)方法将Action派发到Redux的Store中。
  • 3.处理Reducer:Store接收到Action后,会调用所有注册的Reducer函数,将当前的状态和Action传入Reducer中。
  • 4.更新状态:Reducer根据Action的类型,处理状态的变化逻辑,并返回一个新的状态,Redux会将新的状态替代原有的状态,从而更新整个应用的状态。
  • 5.通知订阅者:状态更新后,Redux会通过subScribe(listener)方法注册的监听器,让他们执行相应的回调函数,从而实现对状态变化的监听和响应。

redux的三个核心概念

action

对象,描述要做的事情,项目中的每一个都是一个action

	语法:{type:"命令",payload:"载荷"}

特点:

  • i.只描述做什么。
  • ii.js对象,必须带有type属性,用于区分动作的类型。
  • iii.根据功能的不同,可以携带额外的数据,配合该数据来完成相应的功能。

reducer

函数,用来处理action并更新状态,是Redux状态更新的地方

语法:函数签名:'(prevState,action)=>newState'
const reducer = (state, action) => {switch(action.type){case 'ADD':state['sum'] = action.datareturn [...state]break...}
}

特点:

  • i.注意该函数一定会有返回值,即使状态没有改变也要返回上一次的状态。
  • ii.约定reducer是一个纯函数,并不能包含side effect副作用,例如,不能修改函数参数,不能修改函数外部数据,不能进行异步操作等。
  • iii.对于reducer来说,为了保证reducer是一个纯函数,不要直接修改参数state的值,也就是不要直接修改当前状态,而是根据当前状态值创建新的状态值,不要使用Math.random()/new
    Date()/Date.new()/ajax请求等不纯的操作,不要让reducer执行副作用sideEffect

store

仓库,redux的核心,整合action和reducer

	import {createStore} from 'redux'let store = createStore(reducer)

特点:

  • i.一个应用只有一个store
  • ii.维护应用的状态,获取状态:store.getState()
  • iii.发起状态更新时,store.dispatch(action) iv.创建store时,接收reducer作为参数,const
    store = create Store(reducer)

其他API:

  • i.订阅监听状态变化,const unSubscribe = store.subscribe(()=>{})
  • ii.取消订阅状态变化,unSubscribe()

react-redux概述

概念

在react-redux中,有两个核心概念,即Provider和connect。provider是一个React组件,用于将Redux的Store传递给React应用中的所有组件,从而是的组件可以访问到全局的状态。connect是一个高阶函数,用于将React组件连接到Redux的store,从而实现组件与Redux
store之间的数据传递和状态管理。

如何将React组件连接到Redux store

使用connect函数可以将React组件连接到Redux的store。通过在组件定义时调用connect函数,并传入需要的参数和回调函数,可以将组件与Redux的store进行连接,连接后,组件可以通过prop访问到Redux
Store中的状态,并且可以向Redux store派发action 来修改全局状态。

如何使用React-redux的高阶组件和hooks来简化代码:

react-redux提供了一些高阶组件和hooks,可以帮助简化组件与Redux store之间的交互代码,例如,mapStateToProps和mapDispatchToProps参数可以帮助组件定义如何从redux store中获取状态和派发action的方式,从而减少了在组件中处理Redux store的繁琐代码,此外,React-redux还提供了一些hooks,例如useSelector和useDispatch,可以在函数组件中更方便的访问Redux store的状态和派发action。

react-redux购物车案例
效果:
React-Redux总结含购物车案例

目录结构:
react-redux购物车案例
action/index.js代码

import { ADD_PRODUCT, REMOVE_PRODUCT } from "../constants";export const addProduct = id => ({type: ADD_PRODUCT,payload: id
});export const removeProduct = id => ({type: REMOVE_PRODUCT,payload: id
});cart/cartInte.js代码
import React from "react";
import PropTypes from "prop-types";const CartItem = ({ name, price, quantity, itemTotal, removeProduct }) => (<div className="cartWrapper"><div>{name}</div><div>${price}</div><div>x{quantity}</div><div>= ${itemTotal}</div><div><button onClick={() => removeProduct(name)}>Remove</button></div></div>
);CartItem.propTypes = {name: PropTypes.string.isRequired,price: PropTypes.string.isRequired,quantity: PropTypes.number.isRequired,itemTotal: PropTypes.string.isRequired,removeProduct: PropTypes.func.isRequired
};
export default CartItem;

cart/index.js代码

import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import "./Cart.css";
import CartItem from "./CartItem";
import { getCart, getCartTotal } from "../../reducers";
import { removeProduct } from "../../actions";const Cart = ({ cart, cartTotal, removeProduct }) => (<React.Fragment><h2>Checkout Cart</h2>{cart.map(({ name, price, quantity, itemTotal }) => (<CartItemkey={name}name={name}price={price}quantity={quantity}itemTotal={itemTotal}removeProduct={removeProduct}/>))}<h2>Total</h2><div className="total">${cartTotal}</div></React.Fragment>
);Cart.propTypes = {cart: PropTypes.arrayOf(PropTypes.shape({name: PropTypes.string,price: PropTypes.string,quantity: PropTypes.number,itemTotal: PropTypes.string})),cartTotal: PropTypes.string,removeProduct: PropTypes.func.isRequired
};const mapStateToProps = state => ({cart: getCart(state),cartTotal: getCartTotal(state)
});
export default connect(mapStateToProps, { removeProduct })(Cart);

cart/Cart.css代码

.cartWrapper {display: grid;grid-template-columns: 150px 150px 100px 100px 200px;grid-gap: 10px;white-space: nowrap;
}.total {text-decoration: underline;
}

ProductList/index.js代码

import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import "./ProductList.css";
import Product from "./Product";
import { getProducts } from "../../reducers";
import { addProduct } from "../../actions";const ProductList = ({ products, addProduct }) => (<React.Fragment><h2>Product List</h2>{products.map(({ name, price }) => (<Product key={name} name={name} price={price} addProduct={addProduct} />))}</React.Fragment>
);
// propTypes验证,在给react组件传属性的的时候,定义属性的类型
ProductList.propTypes = {products: PropTypes.arrayOf(PropTypes.shape({name: PropTypes.string.isRequired,price: PropTypes.string.isRequired})),addProduct: PropTypes.func.isRequired
};const mapStateToProps = state => {return { products: getProducts(state) };
};export default connect(mapStateToProps, { addProduct })(ProductList); 

ProductList/product.js代码

import React from "react";
import PropTypes from "prop-types";const Product = ({ name, price, addProduct }) => (<div className="productWrapper"><div>{name}</div><div>{price}</div><div><button onClick={() => addProduct(name)}>Add</button></div></div>
);Product.propTypes = {name: PropTypes.string.isRequired,price: PropTypes.string.isRequired,addProduct: PropTypes.func.isRequired
};export default Product;

ProductList/product.css代码

.productWrapper {display: grid;grid-template-columns: 150px 150px 300px;grid-gap: 10px;
}

reducers/cart.js代码

import { combineReducers } from "redux";
import { ADD_PRODUCT, REMOVE_PRODUCT } from "../constants";//state = [id1, id2]
const initialCartAllIds = [];
// Reducer(状态处理函数)
const cartAllIds = (state = initialCartAllIds, action) => {switch (action.type) {case ADD_PRODUCT: {const newItem = action.payload;if (state.includes(newItem)) return state;return [...state, action.payload];}case REMOVE_PRODUCT: {const unwantedItem = action.payload;return state.filter(item => item !== unwantedItem);}default:return state;}
};// state={id: {quantity: productQuantity}}
const initialCartById = {};
const cartById = (state = initialCartById, action) => {switch (action.type) {case ADD_PRODUCT: {const newItem = action.payload;const newQuantity = state[newItem] ? state[newItem].quantity + 1 : 1;return { ...state, [newItem]: { quantity: newQuantity } };}case REMOVE_PRODUCT: {const unwantedItem = action.payload;const newState = { ...state };delete newState[unwantedItem];return newState;}default:return state;}
};export const cart = combineReducers({cartAllIds,cartById
});export const getCart = (products, cart) => {return cart.cartAllIds.map(productName => {const name = productName;const price = products.productById[productName].price;const quantity = cart.cartById[productName].quantity;const itemTotal = (price * quantity).toFixed(2);return { name, price, quantity, itemTotal };});
};export const getCartTotal = (products, cart) => {return cart.cartAllIds.reduce((pre, cur) => {const price = products.productById[cur].price;const quantity = cart.cartById[cur].quantity;return pre + price * quantity;}, 0).toFixed(2);
};

reducers/Products.js代码

import { combineReducers } from "redux";
import productsData from "../data";// product ID is the product name in this case
// state = {[id]:{name: productName, price: productPrice}}
const initialProductById = (function() {const state = {};productsData.forEach(({ name, price }) => (state[name] = { name, price: price.toFixed(2) }));return state;
})();
const productById = (state = initialProductById, action) => {switch (action.type) {default:return state;}
};// state = [id1, id2]
const initialProductAllIds = productsData.map(product => product.name);
const productAllIds = (state = initialProductAllIds, action) => {switch (action.type) {default:return state;}
};export const products = combineReducers({productById,productAllIds
});export const getProducts = products => {return products.productAllIds.map(key => products.productById[key]);
};

reducers/index.js代码

import { combineReducers } from "redux";
import * as productReducer from "./products";
import * as cartReducer from "./cart";const reducer = combineReducers({products: productReducer.products,cart: cartReducer.cart
});export const getProducts = state => productReducer.getProducts(state.products);export const getCart = state => cartReducer.getCart(state.products, state.cart);export const getCartTotal = state =>cartReducer.getCartTotal(state.products, state.cart);export default reducer;

configureStore.js代码

import { createStore } from "redux";
import reducer from "./reducers";
import { loadState, saveState } from "./localStorage";const persistedState = loadState();const store = createStore(reducer,persistedState,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);store.subscribe(() => {const cartValue = store.getState().cart;saveState({ cart: cartValue });
});export default store;

constants.js代码

export const ADD_PRODUCT = "ADD_PRODUCT";
export const REMOVE_PRODUCT = "REMOVE_PRODUCT";

数据源data.js代码

const products = [{name: "Sledgehammer",price: 125.75},{name: "Axe",price: 190.5},{name: "Bandsaw",price: 562.13},{name: "Chisel",price: 12.9},{name: "Hacksaw",price: 18.45}
];export default products;

index.js中引入store

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import App from "./components/App";
import store from "./configureStore";ReactDOM.render(<Provider store={store}><App /></Provider>,document.getElementById("root")
);

localStorage.js代码

export const loadState = () => {try {const valueJSON = localStorage.getItem("state");return JSON.parse(valueJSON) || undefined;} catch (error) {return undefined;}
};
export const saveState = value => {const valueJSON = JSON.stringify(value);localStorage.setItem("state", valueJSON);
};

效果:
React-Redux总结含购物车案例
新增删除
React-Redux总结含购物车案例
完结~

相关文章:

React-Redux总结含购物车案例

React-Redux总结含购物车案例 reduc简介 redux是react全家桶的一员&#xff0c;它为react给i共可预测化的状态管理机制。redux是将整个应用状态存储到一个地方&#xff0c;成为store,里面存放着一颗树状态(state,tree),组件可以派发dispatch行为action给store,而不是直接通知其…...

攻克组合优化问题!美国DARPA选中全栈量子经典计算公司Rigetti

&#xff08;图片来源&#xff1a;网络&#xff09; 近日&#xff0c;美国量子计算公司Rigetti宣布&#xff0c;它被美国国防高级研究计划局 (DARPA) 选中&#xff0c;加入想象未来量子实际应用 (IMPAQT) 计划&#xff0c;推进先进量子算法的研发&#xff0c;去解决组合优化问…...

Kafka - 深入了解Kafka基础架构:Kafka的基本概念

文章目录 Kafka的基本概念 Kafka的基本概念 我们首先了解一些Kafka的基本概念。 1&#xff09;Producer &#xff1a;消息生产者&#xff0c;就是向kafka broker发消息的客户端2&#xff09;Consumer &#xff1a;消息消费者&#xff0c;向kafka broker获取消息的客户端3&…...

[Docker]二.Docker 镜像,仓库,容器介绍以及详解

一.Docker 镜像,容器,仓库的简单介绍 通俗来讲:镜像相当于VM虚拟机中的ios文件,容器相当于虚拟机系统,仓库相当于系统中的进程或者执行文件,容器是通过镜像创建的 1.镜像 Docker 镜像就是一个 Linux 的文件系统&#xff08; Root FileSystem &#xff09;&#xff0c;这个文…...

软考高级系统架构设计师系列之:案例分析典型试题一

软考高级系统架构设计师系列之:案例分析典型试题一 一、案例分析考试大纲二、结构化软件系统建模1.案例试题2.案例试题分析3.案例试题参考答案三、联合需求分析会议1.案例试题2.案例试题分析3.案例试题参考答案四、电子政务1.案例试题2.案例试题分析3.案例试题参考答案五、软件…...

2023年5个美国代理IP推荐,最佳代理花落谁家?

美国代理IP指的是代理服务器位于美国的IP地址&#xff0c;对于跨境业务来说&#xff0c;这些代理IP地址可以用于隐藏用户的真实IP地址&#xff0c;将其网络流量路由通过美国的服务器&#xff0c;以实现一些特定的目的。由于近年来&#xff0c;面向美国市场的跨境商家越来越多&a…...

github.com/holiman/uint256 源码阅读

github.com/holiman/uint256 源码阅读 // uint256: Fixed size 256-bit math library // Copyright 2018-2020 uint256 Authors // SPDX-License-Identifier: BSD-3-Clause// Package math provides integer math utilities.package uint256import ("encoding/binary&…...

排序-表排序

当我们需要对一个很大的结构体进行排序时&#xff0c;因为正常的排序需要大量的交换&#xff0c;这就会造成时间复杂度的浪费 因此&#xff0c;我们引入指针&#xff0c;通过指针临时变量的方式来避免时间复杂度的浪费 间接排序-排序思路&#xff1a;通过开辟一个指针数组&…...

勒索病毒最新变种.locked1勒索病毒来袭,如何恢复受感染的数据?

引言&#xff1a; 在当今数字化时代&#xff0c;网络威胁不断进化&#xff0c;.locked1勒索病毒就是其中一种常见的恶意软件。这种病毒会加密您的文件&#xff0c;然后勒索赎金以解锁它们。本文将详细介绍.locked1勒索病毒&#xff0c;包括如何恢复被加密的数据文件和如何预防…...

信号补零对信号频谱的影响

文章目录 前言一、 什么是补零二、案例三、补零前仿真及分析1、补零前 MATLAB 源码2、仿真及结果分析①、 x n x_n xn​ 时域图②、 x n x_n xn​ 频谱图 四、补零后仿真及分析1、补6000个零且1000采样点①、 MATLAB 源码②、仿真及结果分析 2、波形分辨率3、补6000个零且7000采…...

【Gan教程 】 什么是变分自动编码器VAE?

名词解释&#xff1a;Variational Autoencoder&#xff08;VAE&#xff09; 一、说明 为什么深度学习研究人员和概率机器学习人员在讨论变分自动编码器时会感到困惑&#xff1f;什么是变分自动编码器&#xff1f;为什么围绕这个术语存在不合理的混淆&#xff1f;本文从两个角度…...

T113-S3-buildroot文件系统tar解压缩gz文件

目录 前言 一、现象描述 二、解决方案 三、tar解压缩.gz文件 总结 前言 本文主要介绍全志T113-S3平台官方SDK&#xff0c;buildroot文件系统tar不支持.gz文件解压缩的问题以及如何配置buildroot文件系统解决该问题的方法介绍。 一、现象描述 在buildroot文件系统中&#xff…...

软件测试面试题:压测时,QPS一直上不去,如何排查?

在进行系统压测时&#xff0c;QPS&#xff08;Queries Per Second&#xff09;即每秒查询数&#xff0c;无法达到预期值是一个常见的问题&#xff0c;本文就来介绍下QPS一直上不去时应该如何排查。 一. 检查硬件资源 CPU使用率 使用top或nmon命令来查看CPU使用率。如果CPU使…...

探索JavaScript ES6+新特性

JavaScript是一门十分流行的编程语言&#xff0c;它不断发展演变以适应现代Web开发需求。ES6&#xff08;也称为ECMAScript 2015&#xff09;是JavaScript的第六个版本&#xff0c;引入了许多令人兴奋的新特性和语法糖。本文将介绍一些ES6中最有趣和实用的特性。 箭头函数 箭…...

Elasticsearch常见错误

一 read_only_allow_delete" : "true" 当我们在向某个索引添加一条数据的时候,可能(极少情况)会碰到下面的报错: {"error": { "root_cause": [ { "type": "cluster_block_exception", "r…...

mysql源码编译安装

下载地址&#xff1a;http://dev.mysql.com/downloads/mysql/5.1.html#downloads 免费版&#xff0c;只能下载mysql社区版。MySQL Community Server 选择合适的版本迚行下载&#xff1a; 安装前&#xff0c;如果不存在mysql 用户,则建立之 [rootlocalhost ~]# useradd mys…...

On Moving Object Segmentation from Monocular Video with Transformers 论文阅读

论文信息 标题&#xff1a;On Moving Object Segmentation from Monocular Video with Transformers 作者&#xff1a; 来源&#xff1a;ICCV 时间&#xff1a;2023 代码地址&#xff1a;暂无 Abstract 通过单个移动摄像机进行移动对象检测和分割是一项具有挑战性的任务&am…...

[AutoSar NVM] 存储架构

依AutoSAR及公开知识辛苦整理&#xff0c;禁止转载。 专栏 《深入浅出AutoSAR》&#xff0c; 全文 2900 字. 图片来源&#xff1a; 知乎 汽车的ECU内存中有很多不同类型的变量&#xff0c;这些变量包括了车辆各个系统和功能所需的数据。大部分变量在ECU掉电后就会丢失&#x…...

ES10 新特性

1. Object.fromEntries Object.fromEntries() 方法把可迭代对象的键值对列表转换为一个对象。 语法: Object.fromEntries(iterable)iterable:类似 Array 、 Map 或者其它实现了可迭代协议的可迭代对象。返回值:一个由该迭代对象条目提供对应属性的新对象。相当于 Object.e…...

宝塔安装脚本

Centos安装脚本 yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh ed8484bec Ubuntu/Deepin安装脚本 wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh && sud…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...