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

【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重点

会话技术&#xff1a; cookie jwt令牌会话技术&#xff1a; jwt生成&#xff1a; Claims&#xff1a;jwt中的第二部分 过滤器&#xff1a; 拦截器&#xff1a; 前端无法识别controller方法&#xff0c;因此存在Dispa什么的...

数据架构图:从数据源到数据消费的全面展示

在这篇文章中&#xff0c;我们将探讨如何通过架构图来展示数据的整个生命周期&#xff0c;从数据源到数据消费。下面是一个使用Mermaid格式的示例数据架构图&#xff0c;展示了数据从源到消费的流动、处理和存储过程。 数据架构图示例 说明 数据源&#xff1a;分为内部数据源&…...

useEffect 与 useLayoutEffect 的区别

useEffect 与 useLayoutEffect 的区别 useEffect和useLayoutEffect是处理副作用的React钩子函数&#xff0c;有以下区别1. 执行时机不同2. 对性能影响不同3. 对渲染的影响不同&#xff1a;4. 使用场景不同 使用建议 useEffect和useLayoutEffect是处理副作用的React钩子函数&…...

OPENCV判断图像中目标物位置及多目标物聚类

文章目录 在最近的项目中&#xff0c;又碰到一个有意思的问题需要通过图像算法来解决。就是显微拍摄的到的医疗图像中&#xff0c;有时候目标物比较偏&#xff0c;也就是在图像的比较偏的位置&#xff0c;需要通过移动样本&#xff0c;将目标物置于视野正中央&#xff0c;然后再…...

分布式理论:拜占庭将军问题

分布式理论&#xff1a;拜占庭将军问题 介绍拜占庭将军的故事将军的难题 解决方案口信消息型拜占庭问题之解流程总结 签名消息型拜占庭问题之解 总结 介绍 拜占庭将军问题是对分布式共识问题的一种情景化描述&#xff0c;由兰伯特于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:百毫秒高弹性的实时事件中心的架构和挑战

作者&#xff1a;胡志广(独鳌) 背景 Serverless 应用引擎 SAE 事件中心主要面向早期的 SAE 控制台只有针对于应用维度的事件&#xff0c;这个事件是 K8s 原生的事件&#xff0c;其实绝大多数的用户并不会关心&#xff0c;同时也可能看不懂。而事件中心&#xff0c;是希望能够…...

人口普查管理系统基于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提供了一个强大的文本转表格的功能&#xff0c;结合VBA可以实现文本快速转换表格。 示例文档如下所示。 现在需要将上述文档内容转换为如下格式的表格&#xff0c;表格内容的起始标志为。 示例代码如下。 Sub SearchTab()Application.DefaultTableSeparator "*&quo…...

力扣题解1870

这道题是一个典型的算法题&#xff0c;涉及计算在限制的时间内列车速度的最小值。这是一个优化问题&#xff0c;通常需要使用二分查找来求解。 题目描述&#xff08;中等&#xff09; 准时到达的列车最小时速 给你一个浮点数 hour &#xff0c;表示你到达办公室可用的总通勤时…...

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中&#xff0c;Run Keyword If 是一个条件执行的关键字&#xff0c;它允许根据某个条件来决定是否执行某个关键字。下面是 Run Keyword If 的基本用法&#xff1a; Run Keyword…...

虚拟机ip突然看不了了

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

LeetCode[中等] 763. 划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍然是 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 &#xff0c;又被称为容器 container &#xff0c;是定义在 java.util 包下的一组接口 int…...

Win10鼠标总是频繁自动失去焦点-非常有效-重启之后立竿见影

针对Win10鼠标频繁自动失去焦点的问题&#xff0c;可以尝试以下解决方案&#xff1a; 一、修改注册表&#xff08;最有效的方法-重启之后立竿见影&#xff09; 打开注册表编辑器&#xff1a; 按下WindowsR组合键&#xff0c;打开运行窗口。在运行窗口中输入“regedit”&#x…...

智能涌现|迎接智能时代,算力产业重构未来

前言 OpenAI首席执行官山姆奥特曼在《智能时代》中描绘了一个令人振奋的未来图景&#xff0c;其中算力产业将扮演至关重要的角色。奥特曼预测&#xff0c;我们可能在“几千天内”迎来超级智能&#xff0c;这一进程将极大加速社会结构的智能化转型。 这一预测与算力产业的未来…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...

ubuntu22.04 安装docker 和docker-compose

首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...