文章目录

      • 一.Redux的基础用法
        • 1.示例:普通网页中的Redux计步器
        • 2.Redux管理数据的流程
        • 3.配套工具和环境准备
          • 3.1.配套工具
          • 3.2.环境准备
        • 4.示例:React项目中的Redux计步器
          • 思路
          • 步骤
            • step1:创建子模块
            • step2:导入子模块
            • step3:注入store实例
            • step4:React组件内使用store中的数据
            • step5:在组件内修改store中的数据
            • step6:优化---定义代参actionCreater来传参
        • 5.示例:使用Redux管理异步状态操作
          • 5.1.创建子模块
          • 5.2.导入子模块
          • 5.3.注入store实例
          • 5.4.在组件中使用
      • 二.Redux案例:某团外卖
        • 1.开发前准备
        • 2.渲染商品分类和商品列表
          • 2.1.创建子模块takeaway
          • 2.2.引入子模块
          • 2.3.把store注入到组件中
          • 2.4.在根组件App中使用和渲染数据
        • 3.点击分类实现高亮
          • 3.1.RTK管理新状态activeIndex
          • 3.2.组件中:点击触发action更新activeIndex,动态控制激活类名
        • 4.点击分类项,实现商品列表的切换显示

一.Redux的基础用法

Redux之于React,类似于Vuex或Pinia之于Vue
Redux可以独立于框架运行,作用是通过几种管理的方式管理应用的状态

1.示例:普通网页中的Redux计步器

由于Redux可以独立于React框架,因此可在网页中使用
步骤:

-step1:定义一个reducer函数
该函数根据当前想要做的修改返回一个新状态,新状态的作用是根据不同的Action对象,返回不同的新state(原则:状态不可变)
示例:function myReducer(state,action){}-step2:使用createStore方法中的reducer函数生成一个store实例对象
示例:const store=Redux.createStore(myReducer)-step3:使用store.subscribe方法,订阅数据的变化
(数据一旦变化就会得到通知)
示例:storesubscribe(()=>{})-step4:使用store.dispatch方法,提交action对象,触发数据变化
dispatch提交一个action来更新状态
示例:store.dispatch({type:'INCREMENT'})-step5:使用store.getState方法,获取最新的状态并更新到视图中
示例:const state=stor.getState()

完整代码:

<!DOCTYPE html>
<html>
<head><title>Redux计数器示例</title><!-- 引入Redux库 --><script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.1/redux.min.js"></script>
</head>
<body><h1>Redux计数器</h1><div><button id="decrement">-</button><span id="counter-value">0</span><button id="increment">+</button></div><script>// 1.定义reducer函数function myReducer(state = { count: 0 }, action) {// 判断type:type的值是从action对象中获取的,而action对象是由dispatch函数生成的。if (action.type === 'INCREMENT') return { count: state.count + 1 };//增加:返回新的状态对象if (action.type === 'DECREMENT') return { count: state.count - 1 };}// 2.使用reducer函数生成store实例const store = Redux.createStore(myReducer);// 3.通过store实例的subscribe订阅数据变化store.subscribe(() => {//该回调会在每次store更新时被调用。// 5.通过store实例的getState方法获取当前状态值,并更新到页面上。const state = store.getState();// 更新页面上的计数器显示document.getElementById('counter-value').textContent = state.count;});// 4.通过store实例的dispatch函数提交action更改状态/*在Redux中修改数据的唯一方式是:通过dispatch提交一个action对象来更新状态*/document.getElementById('increment').addEventListener('click', () => {store.dispatch({ type: 'INCREMENT' });// 提交增加计数器的action对象});document.getElementById('decrement').addEventListener('click', () => {store.dispatch({ type: 'DECREMENT' });// 提交减少计数器的action对象});</script>
</body>
</html>
2.Redux管理数据的流程

在这里插入图片描述
出于职责清晰和数据流向明确的考量,在Redux中,把修改数据的流程分为三个核心概念:

  • state对象:存放管理的数据状态
  • action对象:描述如何修改数据的
  • reducer函数:形参是state和action,根据acton对象的描述生成一个新的state
3.配套工具和环境准备
3.1.配套工具
  • Redux Toolkit插件(RTK)

官方推荐的编写Redux逻辑的方式,是一套工具的集合,能简化书写方式

优点:简化store的配置方式内置immer支持可变式状态修改内置thunk更好的异步创建
  • react-dedux插件

用来链接Redux和React组件的中间件
(Redux向React组件获取状态,React组件向Redux更新状态,都可以通过这个中间件)

3.2.环境准备

创建项目:npx create-react-app my-react-redux(项目名)
进入项目目录:cd my-react-redux
安装配套工具:npm i @reduxjs/toolkit react-redux(插件)
启动项目:npm run start

项目store目录:

src
├─store               用于集中状态管理
│  ├─modules		用于在内部编写业务分类的子store(应用通常有多个子store模块)
│  │  └─index.js      作用是组合modules中的所有子模块并在store中导入 
4.示例:React项目中的Redux计步器
思路
  • Redux store配置:配置counterStore模块,配置根store并导入counterStore模块
  • React组件:注入store(react-redux),使用和修改store中的数据
步骤
step1:创建子模块

使用React ToolkitcreateSlice()方法创建counterStore子模块

//store/modules/counterStore.jsimport {createSlice} from "@reduxjs/toolkit";
const counterstore=createSlice({name:"counter",// 初始化stateinitialState:{//----类似于Vuex中的Storecount:0},// 定义reducer函数reducers:{//----类似于vuex中的mutationsincrement(state){state.count++},decrement(state){state.count--}}
})// 解构出actionCreater函数
const {increment,decrement}=counterstore.actions
// 获取reducer函数
const reducer=counterstore.reducer
// 按需导出actionCreater函数
export {increment,decrement}
// 默认导出reducer函数
export default reducer
step2:导入子模块
//src/store/index.jsimport { configureStore } from "@reduxjs/toolkit";
// 导入子模块的reducer
import counterReducer from "./modules/counterStore";
export const store = configureStore({reducer: {// 注册子模块的reducer函数counter: counterReducer,},
});
step3:注入store实例

react-redux可以链接Redux和React,
其内置的Provider组件可以通过store参数,把创建好的store实例注入到应用中,从而正式建立链接

//src/index.jsimport { Provider } from 'react-redux';
import { store } from './store';
....{/* 注入:将store注入到Provider组件的props中,然后包裹App组件。 */}<Provider store={store}><App /></Provider>
step4:React组件内使用store中的数据

钩子函数useSelector可以把store中的数据映射到组件中

//App.jsimport { useSelector } from "react-redux";
function App() {const { count } = useSelector((state) => state.counter);//来自src/store/index.js的reducer函数return (<div className="App"><h1>Counter: {count}</h1></div>);
}
export default App;
step5:在组件内修改store中的数据

钩子函数useDispatch可以生成dispatch函数,用于提交action对象

//App.js
// 导入actionCreater
import {increment,decrement} from "./store/modules/counterStore";{/* 增加按钮,触发 increment action */}
<button onClick={() => dispatch(increment())}>+</button>
{/* 显示计数器 */}
<h1>Counter: {count}</h1>
{/* 减少按钮,触发 decrement action */}
<button onClick={() => dispatch(decrement())}>-</button>

*子模块counterStore中,在reducers中定义的increment()decrement()被称为actionCreater方法

step6:优化—定义代参actionCreater来传参

App组件新增"addTo10"和"addTo20"两个按钮,
步骤:
* 在reducers的同步修改方法中添加action对象参数
* 在调用actionCreater时传参
* 参数传到action对象的payload属性上
代码:

//counterStore.js
.....// 定义reducer函数reducers:{...addToNum(state,action){state.count+=action.payload}}
// 解构出actionCreater函数
const {increment,decrement,addToNum}=counterstore.actions
// 获取reducer函数
const reducer=counterstore.reducer
// 按需导出actionCreater函数
export {increment,decrement,addToNum}
// 默认导出reducer函数
export default reducer//App.js
import {increment,decrement,addToNum} from "./store/modules/counterStore";<button onClick={() => dispatch(addToNum(10))}>+10</button><button onClick={() => dispatch(addToNum(20))}>+20</button>

总结:

  • useSelector:获取store中的数据
  • useDispatch:获取dispatch方法
  • 得到要提交的action对象:dispatch(increment())//执行store模块中导出的actionCreater方法,即increment()方法
5.示例:使用Redux管理异步状态操作
5.1.创建子模块
//新建store/modules/channelStore.js//step1:创建子模块channelStore.js,代码不变
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";const channelstore=createSlice({name:'channel',initialState:{channelList:[]},reducers:{setChannel(state,action){state.channelList=action.payload}}
})/**异步请求部分 */
// step2:单独封装一个函数
const fetchChannelList=()=>{// const dispatch=useDispatch()// 在函数内部return一个新函数,// 在新函数中封装异步请求,// 并调用actionCreater方法传入异步数据生成一个action对象并使用dispatch方法提交return async (dispatch)=>{const res=await axios.get("https://geek.itheima.net/v1_0/channels")dispatch(setChannel(res.data.data.channels))console.log("res:",res.data.data.channels)}
}// 解构出actionCreater函数
const {setChannel}=channelstore.actions
// 按需导出actionCreater函数和异步请求函数
export {setChannel,fetchChannelList}// 获取reducer函数
const reducers=channelstore.reducer
// 默认导出reducer函数
export default reducers
5.2.导入子模块
//store/index.js
import { configureStore } from "@reduxjs/toolkit";
// 导入子模块的reducer
import counterReducer from "./modules/counterStore";
import channelReducer from "./modules/channelStore";
export const store = configureStore({reducer: {// 注册子模块的reudcer函数counter: counterReducer,channel: channelReducer,},
});
5.3.注入store实例

略,无新增代码

5.4.在组件中使用
//App.js
import { fetchChannelList } from "./store/modules/channelStore";
import { useEffect } from "react";function App(){// 使用 dispatch 来触发 actionconst dispatch = useDispatch();// 使用useEffect来触发异步请求执行useEffect(() => {// 触发 fetchChannelList actiondispatch(fetchChannelList());}, [dispatch]);return(<ul>{channelList.map((item) => (<li key={item.id}>{item.name}</li>))}</ul>)
}

二.Redux案例:某团外卖

在这里插入图片描述
功能:

	* 1.商品列表和分类渲染* 2.添加商品* 3.购物车操作* 4.订单数量统计和高亮实现

思路:
     使用Redux Toolkit(RTK)来管理应用状态,
     组件负责数据渲染和dispatch action

1.开发前准备
step1:从远程仓库克隆本地git clone http://git.itcast.cn/heimaqianduan/redux-meituan.git
step2:安装所有依赖npm i
step3:启动mock服务(内置json-server)npm run serve
step4:启动前端服务npm run start
2.渲染商品分类和商品列表
2.1.创建子模块takeaway
//store/modules/takeaway.js
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";const foodsStore = createSlice({name: "foods",initialState: { foodsList: [] },reducers: {setFoodsList(state, action) {state.foodsList = action.payload;}}
})// 解构createAction方法
const { setFoodsList } = foodsStore.actions// 异步
const fetchFoodsList = () => {return async (dispatch) => {// 获取数据const res = await axios.get("http://localhost:3004/takeaway");// dispatch提交,生成新的action对象dispatch(setFoodsList(res.data))}
}// 按需导出
export { setFoodsList, fetchFoodsList }// 获取reducer
const reducer = foodsStore.reducer
// 默认导出
export default reducer
2.2.引入子模块
//src/store/index.js import { configureStore } from "@reduxjs/toolkit";
// 导入子模块的reducer
import foodsReducer from "./modules/takeaway";export default configureStore({reducer: {// 这里的key要和子模块的name一致foods: foodsReducer,},
});
2.3.把store注入到组件中
//index.jsimport { createRoot } from 'react-dom/client'
import {Provider} from 'react-redux'
import App from './App'
import store from './store'const root = createRoot(document.getElementById('root'))
root.render(// 注入:把store注入到Provider组件中,然后包裹App组件<Provider store={store}><App /></Provider>
)
2.4.在根组件App中使用和渲染数据
//App.js
import { useDispatch,useSelector } from 'react-redux'
import { useEffect } from 'react'
import { fetchFoodsList } from './store/modules/takeaway'//注释掉静态数据const foodsList=[]const App=()=>{/*触发action执行*/const dispatch=useDispatch()// 使用useEffect钩子,在组件加载完成后获取外卖商品列表useEffect(()=>{dispatch(fetchFoodsList())// 派发一个异步获取外卖商品列表的action},[dispatch])/*获取foodsList渲染数据列表*/// 使用useSelector钩子获取foodsList数据const {foodsList} = useSelector(state => state.foods)
}
3.点击分类实现高亮

即点击左边侧边栏中的分类获得高亮选中,右边的对应内容在页面中渲染

高亮和对应的内容如何绑定?

  • 记录当前的点击项activeIndex
  • 动态控制类名,判断条件activeIndex===index

步骤:
    1.RTK管理新状态activeIndex
    2.组件中点击触发action,更改activeIndex
    3.动态控制激活类名显示

3.1.RTK管理新状态activeIndex
//store/modules/takeaway.jsconst foodsStore = createSlice({name: "foods",initialState: {foodsList: [] ,//菜单列表activeIndex: 0 // 当前激活的菜单索引},reducers: {.....// 更改当前激活的菜单索引changeActiveIndex(state, action) {state.activeIndex = action.payload;}}
})
// 解构createAction方法
const { setFoodsList ,changeActiveIndex} = foodsStore.actions
// 按需导出
export { fetchFoodsList, changeActiveIndex }
3.2.组件中:点击触发action更新activeIndex,动态控制激活类名
//src/components/menus/index.jsimport classNames from 'classnames'
import './index.scss'
import { useSelector, useDispatch } from 'react-redux'
import { useEffect } from 'react'
import { changeActiveIndex } from '../../store/modules/takeaway'const Menu = () => {// 从redux中获取数据
const { foodsList,activeIndex} = useSelector((state) => state.foods);
////过滤条件: 过滤出所有标签,并且去除重复的
const menus=foodsList.map(item=>({tag:item.tag,name:item.name}))
const dispatch = useDispatch()// 使用useEffect触发actionuseEffect(() => {dispatch(changeActiveIndex(0))//初始值让渲染有默认选中}, [dispatch])return (<nav className="list-menu">{/* 添加active类名会变成激活状态 */}{menus.map((item, index) => {return (<divonClick={() => {dispatch(changeActiveIndex(index))}}key={item.tag}className={classNames('list-menu-item',activeIndex===index&&'active')}>{item.name}</div>)})}</nav>)
}
export default Menu
4.点击分类项,实现商品列表的切换显示

条件渲染,控制对应项的显隐activeIndex===index&&<div></div>

//App.js
const { foodsList, activeIndex } = useSelector(state => state.foods)
....
{/* 外卖商品列表 */}
{foodsList.map((item, index) => {return (activeIndex === index && <FoodsCategorykey={item.tag}// 列表标题name={item.name}// 列表商品foods={item.foods}/>)
})}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/98018.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/98018.shtml
英文地址,请注明出处:http://en.pswp.cn/web/98018.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

34.Socket编程(UDP)(上)

点分十进制字符串IP 转 32位网络序列IP 分析&#xff1a;1&#xff09;IP转成4字节 2&#xff09;4字节转成网络序列 思路&#xff1a; "192.168.1.1" 进行字符串划分&#xff0c;以 "." 为分割符&#xff0c;分割出"192"&#xff0c;&qu…

Redis的持久化工具包—RDB AOF

文章目录 前言 一、RDB 持久化&#xff08;快照持久化&#xff09; 1. 定义 2. RDB 触发机制 &#xff08;1&#xff09;手动触发 &#xff08;2&#xff09;自动触发 3. RDB 持久化流程 4. RDB 核心配置 5. RDB 优缺点 二、AOF 持久化&#xff08;日志持久化&#xff09; 1. 定…

【Web安全】XXL-JOB框架SRC高频漏洞分析总结

文章目录前言一、核心漏洞分类与技术细节二、漏洞关联利用与攻击路径三、版本演进与修复策略四、安全运维建议五、典型漏洞复现环境搭建六、总结前言 XXL-JOB是国内主流的开源分布式任务调度框架&#xff0c;由徐雪里开发维护&#xff0c;以轻量易用、高可用、适配分布式场景等…

Capacitor 打包后接口访问不到的排查经历

我最近在用 Quasar Capacitor 6 做一个 Android App&#xff0c;前端用的是 Vue3 Quasar&#xff0c;打包交给 Capacitor 去跑在手机的 WebView 里&#xff0c;后端是 FastAPI 提供接口。开发模式下一切顺利&#xff0c;浏览器里访问接口没有任何问题&#xff0c;我甚至觉得打…

【正点原子】Linux应用编程入门~概念及环境介绍

应用编程概念 应用编程&#xff08;也可称为系统编程&#xff09;与驱动编程、裸机编程有何不同&#xff1f;系统调用&#xff1b;何为库函数&#xff1b;应用程序的 main()函数&#xff1b;应用程序开发环境的介绍&#xff1b;系统调用 定义系统调用&#xff08;system call&a…

一、HTML 完全指南:从零开始构建网页

文章目录前言一、 HTML 结构认识 HTML 标签HTML 文件基本结构标签层次结构快速生成代码框架二、 HTML 常见标签详解2.1 注释标签2.2 标题标签 (h1 - h6)2.3 段落标签 (p)2.4 换行标签 (br)2.5 格式化标签2.6 图片标签 (img)2.7 超链接标签 (a)2.8 表格标签基本使用合并单元格2.…

基于POI-TL实现动态Word模板的数据填充:【散点图】特殊处理方案

基于POI-TL实现动态Word模板的数据填充:散点图特殊处理方案 在使用POI-TL进行Word模板动态数据填充时,图表生成是一个常见需求。最近在项目中使用POI-TL处理散点图时遇到了一个特殊问题,经过研究后找到了解决方案,特此记录分享。 问题背景 POI-TL作为一款优秀的Java Wor…

使用node-Express框架写一个学校宿舍管理系统练习项目-前后端分离

今天继续分享一个新的练习项目&#xff0c;是使用node做为后端语言&#xff0c;来写的一个前后端分离项目&#xff1a;学校宿舍管理系统。我们如果想掌握一门编程语言&#xff0c;就是需要大量的练习。所以当我们学习到了一些知识&#xff0c;自己想一下 可以拿学到的知识&…

Kafka 运维实战基本操作含命令与最佳实践

1. 基础概览与工具入口 Kafka 发行包的所有 CLI 工具均在 bin/ 目录下。任何工具不带参数运行都会显示所有可用选项。本文命令默认&#xff1a;--bootstrap-server localhost:9092&#xff1b;生产请替换为你的控制面或内网 VIP。 2. 主题管理&#xff08;创建 / 修改 / 删除 /…

贪心算法应用:航班起降问题详解

Java中的贪心算法应用&#xff1a;航班起降问题详解 贪心算法是一种在每一步选择中都采取当前状态下最优的选择&#xff0c;从而希望导致全局最优解的算法策略。在航班起降问题中&#xff0c;贪心算法可以有效地解决机场跑道调度问题&#xff0c;即如何安排航班的起降顺序以最大…

uniapp scroll-view 设置scrollTop无效

当我们使用 scroll-view的scroll-top的时候 默认想让它回到顶部&#xff0c;当我们设置值为0的时候会不生效&#xff0c;在实际运用过程中&#xff0c;发现设置了scroll-top无效&#xff0c;滚动条位置并没有发生变化&#xff0c;是因为微信小程序的官方框架处于性能考虑&#…

网络与通信

1.TCP协议与UDP协议TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;和 UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是 TCP/IP 协议族中两种核心的传输层协议&#xff0c;它们在数据传输方式、可靠性、适…

Node.js中package.json详解

1. name&#xff08;名称&#xff09; 如果你计划发布你的包&#xff0c;package.json 中最重要的字段是 name 和 version&#xff0c;因为它们是必需的。name 和 version 共同组成一个假定完全唯一的标识符。包的更改应伴随版本号的更新。如果你不打算发布包&#xff0c;那么…

代码随想录第14天| 翻转、对称与深度

226.翻转二叉树 &#xff08;优先掌握递归&#xff09; 题目链接/文章讲解/视频讲解&#xff1a;翻转二叉树 交换的是指针&#xff0c;而不是数值&#xff0c;如果用数值做交换&#xff0c;需要交换的节点下面无法很好的操作。 使用递归来实现&#xff0c;但要提前清除是什么顺…

DNS-Windows上使用DNS

DNS-Windows上使用DNS一、查看与修改DNS配置1.1、查看当前DNS服务器设置1.2、临时修改 DNS 服务器&#xff08;命令行&#xff09;二、DNS缓存相关操作2.1、查看DNS缓存内容2.2、 刷新 DNS 缓存&#xff08;清除过期记录&#xff09;三、测试域名解析&#xff08;nslookup 工具…

3dsMax 2026 .NET Core 8 转型下的Maxscript脚本开发:动态编译模块的重构策略与兼容性升级路径

3ds Max 长期以来一直提供出色的 .NET 集成,使 Maxscript 能够无缝利用任何 .NET 库的强大功能。部分开发者在工具中广泛使用了 .NET 功能。 之前,3ds Max 依赖于 .NET Framework 4.8 并且最近更新到了 4.8.1,用于 2025 版本的发布。然而,随着 3ds Max 2026 的推出,Autod…

golang 做webrtc开发核心

在Golang中进行WebRTC开发&#xff0c;核心在于理解WebRTC协议的工作原理以及如何利用Go生态中的库来实现关键功能。以下是Golang WebRTC开发的核心要点&#xff1a; WebRTC基础概念 了解ICE&#xff08;Interactive Connectivity Establishment&#xff09;协议用于NAT穿越掌握…

RabbitMQ 异步化抗洪实战

说明&#xff1a;本文仅展示架构思路与安全片段&#xff0c;所有敏感字段已用占位符&#xff1b;不含可直接复刻的生产细节。数据与接口均为演示/虚拟。0. 背景与目标长耗时/不确定接口&#xff08;如对接第三方机器人平台&#xff09;的同步阻塞&#xff0c;容易造成请求堆积与…

接口返回 2 万条数据,easy-trans导致多了20s耗时排查过程

内网访问排版核料详情功能&#xff0c;用户反馈要等十几秒排查 sql&#xff1a;sql 比较简单排查内存计算&#xff1a;arthus trace 类名 方法名 总耗时2s排查页面渲染是否缓慢&#xff1a;F12 查看接口 等待服务器响应 20s 下载时间 30s, 故不考虑渲染问题排查请求响应日志打…

AIGC入门,手搓大模型客户端与MCP交互

概述 在现代应用开发中&#xff0c;将大语言模型&#xff08;LLM&#xff09;与专用工具服务相结合&#xff0c;可以构建出既能理解自然语言&#xff0c;又能准确执行专业任务的智能代理。本文介绍一个基于 MCP&#xff08;Model Context Protocol&#xff09;协议和 Ollama 本…