【React】入门Day03 —— Redux 与 React Router 核心概念及应用实例详解
1. Redux 介绍
// 创建一个简单的Redux store
const { createStore } = Redux;// reducer函数
function counterReducer(state = { count: 0 }, action) {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 };case 'DECREMENT':return { count: state.count - 1 };default:return state;}
}// 创建store实例
const store = createStore(counterReducer);// 订阅数据变化
store.subscribe(() => {console.log(store.getState());
});// 触发数据变化
store.dispatch({ type: 'INCREMENT' });
-
概念
- 是 React 常用的集中状态管理工具,可独立于框架运行,类似于 Vue 中的 Pinia(Vuex)。
- 通过集中管理方式管理应用状态。
-
使用原因
- 独立于组件,无视层级关系,简化通信。
- 单向数据流清晰,易于定位 bug。
- 调试工具配套良好,方便调试。
2. Redux 快速体验
<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>
<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
<script>// 定义reducer函数 function counterReducer (state = { count: 0 }, action) {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 }case 'DECREMENT':return { count: state.count - 1 }default:return state}}const store = Redux.createStore(counterReducer);store.subscribe(() => {document.getElementById('count').innerText = store.getState().count;});const inBtn = document.getElementById('increment');inBtn.addEventListener('click', () => {store.dispatch({ type: 'INCREMENT' });});const dBtn = document.getElementById('decrement');dBtn.addEventListener('click', () => {store.dispatch({ type: 'DECREMENT' });});
</script>
-
计数器实现
- 定义 reducer 函数,根据 action 返回新状态。
- 使用 createStore 传入 reducer 生成 store 实例。
- 用 store 的 subscribe 方法订阅数据变化。
- 通过 store 的 dispatch 方法提交 action 触发变化。
- 利用 store 的 getState 方法获取最新状态更新视图。
-
数据流架构
// 定义state const initialState = { count: 0 };// 定义action const incrementAction = { type: 'INCREMENT' };// 定义reducer function counterReducer(state = initialState, action) {switch (action.type) {case 'INCREMENT':return { count: state.count + 1 };default:return state;} }
- 包含 state(存放数据对象)、action(描述数据修改对象)、reducer(根据 action 更新 state 的函数)三个核心概念。
3. Redux 与 React
# 创建React项目
npx create-react-app react-redux # 安装配套工具
npm i @reduxjs/toolkit react-redux # 启动项目
npm run start
-
环境准备
- 安装 Redux Toolkit(RTK)和 react-redux。
- 使用 CRA 创建 React 项目,安装配套工具并启动。
- 设计 store 目录结构,包括单独的 store 目录和内部的 modules 目录,入口文件组合子模块并导出 store。
-
实现 counter
// counterStore.js import { createSlice } from '@reduxjs/toolkit';const counterStore = createSlice({name: 'counter',initialState: { count: 1 },reducers: {increment(state) {state.count++;},decrement(state) {state.count--;}} });const { increment, decrement } = counterStore.actions; const counterReducer = counterStore.reducer; export { increment, decrement }; export default counterReducer;// store.js import { configureStore } from '@reduxjs/toolkit'; import counterReducer from './modules/counterStore'; export default configureStore({reducer: {counter: counterReducer} });// App.jsx import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import store from './store'; import { Provider } from 'react-redux'; ReactDOM.createRoot(document.getElementById('root')).render(<Provider store={store}><App /></Provider> );// 在组件中使用store数据 import { useSelector } from 'react-redux'; const count = useSelector(state => state.counter.count);// 在组件中修改store数据 import { useDispatch } from 'react-redux'; const dispatch = useDispatch(); dispatch(increment());
- 使用 React Toolkit 创建 counterStore,定义模块名称、初始数据和修改数据的同步方法。
- 为 React 注入 store,使用 Provider 组件传递 store 实例。
- React 组件中用 useSelector 获取 store 数据,用 useDispatch 修改 store 数据。
-
提交 action 传参
// reducer函数 function counterReducer(state = { count: 0 }, action) {switch (action.type) {case 'INCREMENT_WITH_PARAM':return { count: action.payload.targetCount };default:return state;} }// 触发action并传递参数 const targetCount = 10; store.dispatch({ type: 'INCREMENT_WITH_PARAM', payload: { targetCount } });
- 在 reducers 同步修改方法中添加 action 对象参数,调用 actionCreater 时传递参数到 action 对象的 payload 属性。
-
异步 action 处理
// channelStore.js import { createSlice } from '@reduxjs/toolkit'; import axios from 'axios';const channelStore = createSlice({name: 'channel',initialState: { channelList: [] },reducers: {setChannelList(state, action) {state.channelList = action.payload;}} });const { setChannelList } = channelStore.actions; const url = 'http://geek.itheima.net/v1_0/channels'; const fetchChannelList = () => {return async (dispatch) => {const res = await axios.get(url);dispatch(setChannelList(res.data.data.channels));} }; export { fetchChannelList }; const channelReducer = channelStore.reducer; export default channelReducer;// App.jsx import { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { fetchChannelList } from './store/channelStore';function App() {const { channelList } = useSelector(state => state.channel);useEffect(() => {dispatch(fetchChannelList());}, [dispatch]);return (<div className="App"><ul>{channelList.map(task => <li key={task.id}>{task.name}</li>)}</ul></div>); } export default App;
- 创建 store 配置同步方法,单独封装函数,在新函数中封装异步请求获取数据并调用同步 actionCreater 生成 action 对象提交。
4. Redux 调试
- 官方提供调试工具,支持实时 state 信息展示和 action 提交信息查看。
5. 路由快速上手
// 假设已有一个简单的React组件结构
import React from 'react';
import ReactDOM from 'react-dom/client';// 定义两个简单组件
const LoginComponent = () => <div>登录页面内容</div>;
const ArticleComponent = () => <div>文章页面内容</div>;// 这里模拟路由配置(实际使用React Router的配置方式会更复杂)
const routes = [{ path: '/login', component: LoginComponent },{ path: '/article', component: ArticleComponent }
];// 根据当前路径渲染相应组件(这里是简化的逻辑,实际需要根据React Router的机制来实现)
const App = () => {const currentPath = window.location.pathname;const ComponentToRender = routes.find(route => route.path === currentPath)?.component || null;return <>{ComponentToRender}</>;
};ReactDOM.createRoot(document.getElementById('root')).render(<App />);
-
前端路由概念
- 一个路径对应一个组件,访问路径时对应组件在页面渲染。
-
开发环境创建
# 使用CRA创建项目 npm create-react-app react-router-pro# 安装最新的ReactRouter包 npm i react-router-dom# 启动项目 npm run start
- 使用 CRA 创建项目,安装 React Router 包,启动项目。
-
快速开始
import React from 'react'; import ReactDOM from 'react-dom/client'; import { createBrowserRouter, RouterProvider } from 'react-router-dom';const router = createBrowserRouter([{path: '/login',element: <div>登录</div>},{path: '/article',element: <div>文章</div>}, ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} /> );
- 使用
createBrowserRouter
创建路由,配置路径和对应组件,通过RouterProvider
渲染路由。
- 使用
6. 抽象路由模块
// 假设这是一个简单的路由模块文件
import { createBrowserRouter, RouterProvider } from 'react-router-dom';// 定义各个路由组件
const HomeComponent = () => <div>首页</div>;
const AboutComponent = () => <div>关于我们</div>;
const ContactComponent = () => <div>联系我们</div>;// 创建路由配置
const router = createBrowserRouter([{path: '/',element: HomeComponent},{path: '/about',element: AboutComponent},{path: '/contact',element: ContactComponent}
]);// 导出路由配置供其他文件使用
export default router;
- (文档中未详细说明相关内容,可能需要进一步查看实际模块相关代码)
7. 路由导航
-
概念
- 路由系统中多个路由间需进行跳转及参数传递通信。
-
声明式导航
import React from 'react'; import { Link } from 'react-router-dom';const NavMenu = () => (<nav><Link to="/home">首页</Link><Link to="/about">关于</Link><Link to="/contact">联系</Link></nav> );
- 通过
<Link/>
组件,指定to
属性为路由路径实现跳转,传参可字符串拼接。
- 通过
-
编程式导航
import React from 'react'; import { useNavigate } from 'react-router-dom';const LoginButton = () => {const navigate = useNavigate();const handleLogin = () => {// 假设这里是登录逻辑,登录成功后进行跳转navigate('/dashboard');};return <button onClick={handleLogin}>登录</button>; };
- 使用
useNavigate
钩子获取导航方法,调用navigate
方法传入路径实现跳转,更灵活。
- 使用
8. 导航传参
import React from 'react';
import { useNavigate } from 'react-router-dom';const ProductDetailButton = () => {const navigate = useNavigate();const productId = 123; // 假设这是一个产品IDconst handleNavigate = () => {navigate(`/product/${productId}`);};return <button onClick={handleNavigate}>查看产品详情</button>;
};
- (文档中未详细说明相关内容,可能需要进一步查看实际传参相关代码)
9. 嵌套路由配置
-
概念
- 一级路由中内嵌其他路由为嵌套路由,内嵌的为二级路由。
import React from 'react'; import { createBrowserRouter, RouterProvider } from 'react-router-dom';// 定义子路由组件 const SubPage1 = () => <div>子页面1</div>; const SubPage2 = () => <div>子页面2</div>;// 一级路由组件 const MainPage = () => <div>主页面</div>;// 创建嵌套路由配置 const router = createBrowserRouter([{path: '/main',element: MainPage,children: [{path: 'sub1',element: SubPage1},{path: 'sub2',element: SubPage2}]} ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} /> );
- 一级路由中内嵌其他路由为嵌套路由,内嵌的为二级路由。
-
配置步骤
- 使用
children
属性配置嵌套关系,用<Outlet/>
组件配置二级路由渲染位置。import React from 'react'; import { createBrowserRouter, RouterProvider, Outlet } from 'react-router-dom';// 定义子路由组件 const SubPage1 = () => <div>子页面1</div>; const SubPage2 = () => <div>子页面2</div>;// 一级路由组件 const MainPage = () => <div>主页面,这里可以放置一些通用的内容,子页面会在Outlet处渲染</div>;// 创建嵌套路由配置 const router = createBrowserRouter([{path: '/main',element: MainPage,children: [{path: 'sub1',element: SubPage1},{path: 'sub2',element: SubPage2}]} ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router}><MainPage><Outlet /></MainPage></RouterProvider> );
- 使用
-
默认二级路由
- 访问一级路由时,二级路由去掉路径,设置
index
属性为true
可默认渲染。import React from 'react'; import { createBrowserRouter, RouterProvider, Outlet } from 'react-router-dom';// 定义子路由组件 const SubPage = () => <div>默认子页面</div>;// 一级路由组件 const MainPage = () => <div>主页面,这里可以放置一些通用的内容,子页面会在Outlet处渲染</div>;// 创建嵌套路由配置 const router = createBrowserRouter([{path: '/main',element: MainPage,children: [{path: '',index: true,element: SubPage}]} ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router}><MainPage><Outlet /></MainPage></RouterProvider> );
- 访问一级路由时,二级路由去掉路径,设置
-
404 路由配置
- 准备
NotFound
组件,在路由表末尾用*
作为路径配置路由。import React from 'react'; import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import NotFoundComponent from './NotFoundComponent';// 其他路由配置 const router = createBrowserRouter([//...其他路由{path: '*',element: NotFoundComponent} ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} /> );
- 准备
-
路由模式
- 常用
history
模式和hash
模式。history
模式:url
表现为url/login
,基于history
对象和pushState
事件,需后端支持。import React from 'react'; import { createBrowserRouter, RouterProvider } from 'react-router-dom';// 假设后端已正确配置处理history模式的路由请求const router = createBrowserRouter([{path: '/login',element: <div>登录页面内容</div>},{path: '/article',element: <div>文章页面内容</div>} ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} /> );
hash
模式:url
表现为url/#/login
,监听hashChange
事件,无需后端支持。import React from 'react'; import { createHashRouter, RouterProvider } from 'react-router-dom';const router = createHashRouter([{path: '/login',element: <div>登录页面内容</div>},{path: '/article',element: <div>文章页面内容</div>} ]);ReactDOM.createRoot(document.getElementById('root')).render(<RouterProvider router={router} /> );
- 常用
相关文章:
【React】入门Day03 —— Redux 与 React Router 核心概念及应用实例详解
1. Redux 介绍 // 创建一个简单的Redux store const { createStore } Redux;// reducer函数 function counterReducer(state { count: 0 }, action) {switch (action.type) {case INCREMENT:return { count: state.count 1 };case DECREMENT:return { count: state.count -…...
u2net网络模型训练自己数据集
单分类 下载项目源码 项目源码 准备数据集 将json转为mask json_to_dataset.py import cv2 import json import numpy as np import os import sys import globdef func(file):with open(file, moder, encoding"utf-8") as f:configs json.load(f)shapes configs…...

登录功能开发 P167重点
会话技术: cookie jwt令牌会话技术: jwt生成: Claims:jwt中的第二部分 过滤器: 拦截器: 前端无法识别controller方法,因此存在Dispa什么的...

数据架构图:从数据源到数据消费的全面展示
在这篇文章中,我们将探讨如何通过架构图来展示数据的整个生命周期,从数据源到数据消费。下面是一个使用Mermaid格式的示例数据架构图,展示了数据从源到消费的流动、处理和存储过程。 数据架构图示例 说明 数据源:分为内部数据源&…...
useEffect 与 useLayoutEffect 的区别
useEffect 与 useLayoutEffect 的区别 useEffect和useLayoutEffect是处理副作用的React钩子函数,有以下区别1. 执行时机不同2. 对性能影响不同3. 对渲染的影响不同:4. 使用场景不同 使用建议 useEffect和useLayoutEffect是处理副作用的React钩子函数&…...

OPENCV判断图像中目标物位置及多目标物聚类
文章目录 在最近的项目中,又碰到一个有意思的问题需要通过图像算法来解决。就是显微拍摄的到的医疗图像中,有时候目标物比较偏,也就是在图像的比较偏的位置,需要通过移动样本,将目标物置于视野正中央,然后再…...
分布式理论:拜占庭将军问题
分布式理论:拜占庭将军问题 介绍拜占庭将军的故事将军的难题 解决方案口信消息型拜占庭问题之解流程总结 签名消息型拜占庭问题之解 总结 介绍 拜占庭将军问题是对分布式共识问题的一种情景化描述,由兰伯特于1082首次发表《The Byzantine Generals Prob…...
从零开始Ubuntu24.04上Docker构建自动化部署(三)Docker安装Nginx
安装nginx sudo docker pull nginx 启动nginx 宿主机创建目录 sudo mkdir -p /home/nginx/{conf,conf.d,html,logs} 先启动nginx sudo docker run -d --name mynginx -p 80:80 nginx 宿主机上拷贝docker上nginx服务上文件到本地目录 sudo docker cp mynginx:/etc/nginx/ngin…...

阿里云 SAE Web:百毫秒高弹性的实时事件中心的架构和挑战
作者:胡志广(独鳌) 背景 Serverless 应用引擎 SAE 事件中心主要面向早期的 SAE 控制台只有针对于应用维度的事件,这个事件是 K8s 原生的事件,其实绝大多数的用户并不会关心,同时也可能看不懂。而事件中心,是希望能够…...

人口普查管理系统基于VUE+SpringBoot+Spring+SpringMVC+MyBatis开发设计与实现
目录 1. 系统概述 2. 系统架构设计 3. 技术实现细节 3.1 前端实现 3.2 后端实现 3.3 数据库设计 4. 安全性设计 5. 效果展示 编辑编辑 6. 测试与部署 7. 示例代码 8. 结论与展望 一个基于 Vue Spring Boot Spring Spring MVC MyBatis 的人口普查管理…...

使用VBA快速将文本转换为Word表格
Word提供了一个强大的文本转表格的功能,结合VBA可以实现文本快速转换表格。 示例文档如下所示。 现在需要将上述文档内容转换为如下格式的表格,表格内容的起始标志为。 示例代码如下。 Sub SearchTab()Application.DefaultTableSeparator "*&quo…...

力扣题解1870
这道题是一个典型的算法题,涉及计算在限制的时间内列车速度的最小值。这是一个优化问题,通常需要使用二分查找来求解。 题目描述(中等) 准时到达的列车最小时速 给你一个浮点数 hour ,表示你到达办公室可用的总通勤时…...
D3.js数据可视化基础——基于Notepad++、IDEA前端开发
实验:D3.js数据可视化基础 1、实验名称 D3数据可视化基础 2、实验目的 熟悉D3数据可视化的使用方法。 3、实验原理 D3 的全称是(Data-Driven Documents),是一个被数据驱动的文档,其实就是一个 JavaScript 的函数库,使用它主要是用来做数据可视化的。本次实…...
在Robot Framework中Run Keyword If的用法
基本用法使用 ELSE使用 ELSE IF使用内置变量使用Python表达式本文永久更新地址: 在Robot Framework中,Run Keyword If 是一个条件执行的关键字,它允许根据某个条件来决定是否执行某个关键字。下面是 Run Keyword If 的基本用法: Run Keyword…...

虚拟机ip突然看不了了
打印大致如下: 解决办法 如果您发现虚拟机的IP地址与主机不在同一网段,可以采取的措施之一是调整网络设置。将虚拟机的网络模式更改为桥接模式,这样它就会获得与主机相同的IP地址,从而处于同一网段。或者,您可以使用…...

LeetCode[中等] 763. 划分字母区间
给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。 返回一个表示每个字符串片段的长度的列表。 思路 贪心…...
Java LeetCode每日一题
997. 找到小镇的法官 package JavaExercise20241002;public class JavaExercise {public static void main(String[] args) {int[][] array {{1,3},{2,3},{3,1}};Solution solution new Solution();System.out.println(solution.findJudge(3, array));} }class Solution {pu…...
数据结构--集合框架
目录 1. 什么是集合框架 2. 背后所涉及的数据结构以及算法 2.1 什么是数据结构 2.2 容器背后对应的数据结构 1. 什么是集合框架 Java 集合框架 Java Collection Framework ,又被称为容器 container ,是定义在 java.util 包下的一组接口 int…...

Win10鼠标总是频繁自动失去焦点-非常有效-重启之后立竿见影
针对Win10鼠标频繁自动失去焦点的问题,可以尝试以下解决方案: 一、修改注册表(最有效的方法-重启之后立竿见影) 打开注册表编辑器: 按下WindowsR组合键,打开运行窗口。在运行窗口中输入“regedit”&#x…...
智能涌现|迎接智能时代,算力产业重构未来
前言 OpenAI首席执行官山姆奥特曼在《智能时代》中描绘了一个令人振奋的未来图景,其中算力产业将扮演至关重要的角色。奥特曼预测,我们可能在“几千天内”迎来超级智能,这一进程将极大加速社会结构的智能化转型。 这一预测与算力产业的未来…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...

react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...