Web学习笔记-React(路由)
笔记内容转载自 AcWing 的 Web 应用课讲义,课程链接:AcWing Web 应用课。
CONTENTS
- 1. Web分类
- 2. Route组件
- 3. URL中传递参数
- 4. Search Params传递参数
- 5. 重定向
- 6. 嵌套路由
本节内容是如何将页面和 URL 一一对应起来。
1. Web分类
Web 页面可以分为两大类:
- 静态页面:页面里的数据是写死的,即整个文件存放在服务器上,当用户访问 URL 时,服务器原封不动地将页面信息传给前端。
- 动态页面:页面里的数据是动态填充的,即服务器上存的是页面的模板,数据是存到数据库里的,当用户打开页面时,会动态将这个页面拼接起来。现在一般都是动态页面。
- 后端渲染:数据在后端填充,即模板与数据的拼接操作是在服务器端进行的。客户端向服务器端发送 URL,服务器端返回拼接好的页面。
- 前端渲染:数据在前端填充,即模板与数据的拼接操作是在用户的浏览器进行的。第一次打开页面时,客户端向服务器端发送 URL,服务器端返回所有页面的模板,渲染的时候根据当前需要哪些数据再向服务器端请求数据;第二次打开页面时,直接用 JS 刷新当前页面,不一定会向后端发送请求。
2. Route组件
Route 组件可以让我们的前端页面也可以和 URL 唯一对应起来,使得前端渲染的模式看起来假装和后端渲染是一样的。
我们创建一个新的项目 route-app
,然后用 VS Code 打开项目:
create-react-app route-app
配置一下环境:
- VS Code 安装插件:
Auto Import - ES6, TS, JSX, TSX
- 安装 Route 组件(在项目根目录下安装,安装好后重启一下 VS Code):
npm i react-router-dom
- 安装 Bootstrap:
npm i bootstrap
Route 组件介绍:
BrowserRouter
:所有需要路由的组件,都要包裹在BrowserRouter
组件内;Link
:跳转到某个链接(但是没有向后端发请求),to
属性表示跳转到的链接;Routes
:类似于 C++ 中的switch
,但是只匹配第一个路径,即从前往后看每个Route
,判断当前链接是否等于Route
中的链接,如果是则渲染Route
中的组件,之后的就不继续往下判断了;Route
:路由,path
属性表示路径,element
属性表示路由到的内容(组件)。
我们先创建好我们项目的根组件 App
、导航栏 NavBar
,以及多个子页面的组件:Home
、Linux
、Django
、Web
、NotFound
。
NavBar
代码如下:
import React, { Component } from 'react';class NavBar extends Component {state = { } render() {return (<nav className="navbar navbar-expand-lg bg-body-tertiary"><div className="container-fluid"><a className="navbar-brand" href="/">讲义</a><button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation"><span className="navbar-toggler-icon"></span></button><div className="collapse navbar-collapse" id="navbarNavAltMarkup"><div className="navbar-nav"><a className="nav-link active" aria-current="page" href="/">Home</a><a className="nav-link" href="/linux">Linux</a><a className="nav-link" href="/django">Django</a><a className="nav-link" href="/web">Web</a></div></div></div></nav>);}
}export default NavBar;
App
代码如下:
import React, { Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import NotFound from './notfound';class App extends Component {state = { } render() {return (<React.Fragment><NavBar /></React.Fragment>);}
}export default App;
Home
、Linux
、Django
、Web
、NotFound
代码类似,只展示一个:
import React, { Component } from 'react';class Home extends Component {state = { } render() {return (<h1>Home</h1>);}
}export default Home;
现在我们根据 URL 来渲染页面,注意此时还是属于后端渲染,每次都会重新加载页面,我们修改 App
:
import React, { Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import NotFound from './notfound';
import { Routes, Route } from 'react-router-dom'class App extends Component {state = { } render() {return (<React.Fragment><NavBar /><Routes> // 一定要将路由包含在Routes里面,里面会有很多个Route<Route path='/' element={<Home />} /> // 如果链接为'/'就跳到Home组件<Route path='/linux' element={<Linux />} /><Route path='/django' element={<Django />} /><Route path='/web' element={<Web />} /></Routes></React.Fragment>);}
}export default App;
现在我们用 Link
替换 NavBar
中的链接标签 a
,这样就变为了前端渲染:
import React, { Component } from 'react';
import { Link } from 'react-router-dom'class NavBar extends Component {state = { } render() {return (<nav className="navbar navbar-expand-lg bg-body-tertiary"><div className="container-fluid"><Link className="navbar-brand" to="/">讲义</Link><button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation"><span className="navbar-toggler-icon"></span></button><div className="collapse navbar-collapse" id="navbarNavAltMarkup"><div className="navbar-nav"><Link className="nav-link" aria-current="page" to="/">Home</Link><Link className="nav-link" to="/linux">Linux</Link><Link className="nav-link" to="/django">Django</Link><Link className="nav-link" to="/web">Web</Link></div></div></div></nav>);}
}export default NavBar;
3. URL中传递参数
当网站的页面数量很多的时候,我们肯定不可能去写那么多个 Route
。
假设我们现在有几篇 Web 讲义,第 i i i 篇的路由链接为:/web/content/i
:
import React, { Component } from 'react';
import { Link } from 'react-router-dom'class Web extends Component {state = {webs: [{id: 1, title: 'HTML基础标签'},{id: 2, title: 'CSS'},{id: 3, title: 'JavaScript'},{id: 4, title: '中期项目-拳皇'},{id: 5, title: 'React'},]} render() {return (<React.Fragment><h1>Web</h1><hr /><div>{this.state.webs.map(web => (<div key={web.id}><Link to={`/web/content/${web.id}`}>{web.id + '.' + web.title}</Link></div>))}</div></React.Fragment>);}
}export default Web;
我们先实现一下讲义内容的组件 WebContent
:
import React, { Component } from 'react';class WebContent extends Component {state = { } render() {return (<h1>Web Content</h1>);}
}export default WebContent;
然后在 App
中写一下路由(我们不能写多个 <Route path='/web/content/i' element={<WebContent />} />
,而是用 :xxx
):
import React, { Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import WebContent from './webcontent';
import NotFound from './notfound';
import { Routes, Route } from 'react-router-dom'class App extends Component {state = { } render() {return (<React.Fragment><NavBar /><div className='container'><Routes> // 一定要将路由包含在Routes里面,里面会有很多个Route<Route path='/' element={<Home />} /> // 如果链接为'/'就跳到Home组件<Route path='/linux' element={<Linux />} /><Route path='/django' element={<Django />} /><Route path='/web' element={<Web />} /><Route path='/web/content/:chapter' element={<WebContent />} /></Routes></div></React.Fragment>);}
}export default App;
现在我们如何在 WebContent
中获取 :chapter
参数呢?先看一下函数组件获取参数的方式,可以直接用 useParams
函数获取参数:
import React from 'react';
import { useParams } from 'react-router-dom';const WebContent = () => {console.log(useParams())return (<h1>Web Content - {useParams().chapter}</h1>);
}export default WebContent;
如果是类组件的话就需要先套一层函数组件,然后把 useParams
函数作为参数传给自己:
import React, { Component } from 'react';
import { useParams } from 'react-router-dom';class WebContent extends Component {state = { } render() {console.log(this.props.params)return (<h1>Web Content - {this.props.params.chapter}</h1>);}
}export default (props) => (<WebContent{...props} // 先把函数组件里面的属性展开params={useParams()}/>
);
4. Search Params传递参数
如果网站链接形式为:/web/content?chapter=3
,这样的链接也可以获取参数。
我们先改一下 Web
中的链接形式:
import React, { Component } from 'react';
import { Link } from 'react-router-dom'class Web extends Component {state = {webs: [...]} render() {return (<React.Fragment><h1>Web</h1><hr /><div>{this.state.webs.map(web => (<div key={web.id}><Link to={`/web/content?chapter=${web.id}`}>{web.id + '.' + web.title}</Link></div>))}</div></React.Fragment>);}
}export default Web;
然后在 WebContent
中获取链接的参数:
import React, { Component } from 'react';
import { useSearchParams } from 'react-router-dom';
import { Link } from 'react-router-dom'class WebContent extends Component {state = {searchParams: this.props.params[0], // 用于获取某一个参数setSearchParams: this.props.params[1], // 用于设置链接里的参数,重新渲染页面};render() {console.log(this.state.searchParams.get('chapter'))return (<React.Fragment><h1>Web Content - {this.state.searchParams.get('chapter')}</h1><hr /><div>讲义内容</div><hr /><Link to='/web'>返回上一级</Link></React.Fragment>);}
}export default (props) => (<WebContent{...props} // 先把函数组件里面的属性展开params={useSearchParams()}/>
);
函数组件的写法如下:
import React from 'react';
import { useSearchParams } from 'react-router-dom';
import { Link } from 'react-router-dom'const WebContent = () => {let [searchParams, setSearchParams] = useSearchParams();console.log(searchParams.get('chapter'));return (<React.Fragment><h1>Web Content - {searchParams.get('chapter')}</h1><hr /><div>讲义内容</div><hr /><Link to='/web'>返回上一级</Link></React.Fragment>);
}export default WebContent;
5. 重定向
当打开一个不存在的链接时应该重定向到 404 Not Found
,我们先将这个路由定义出来:<Route path='/404' element={<NotFound />} />
。
使用 Navigate
组件可以重定向,我们可以使用通配符 *
匹配其余的所有路径,然后将其重定向到 /404
页面即可:
import React, { Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import WebContent from './webcontent';
import NotFound from './notfound';
import { Routes, Route, Navigate } from 'react-router-dom'class App extends Component {state = { } render() {return (<React.Fragment><NavBar /><div className='container'><Routes> // 一定要将路由包含在Routes里面,里面会有很多个Route<Route path='/' element={<Home />} /> // 如果链接为'/'就跳到Home组件<Route path='/linux' element={<Linux />} /><Route path='/django' element={<Django />} /><Route path='/web' element={<Web />} /><Route path='/web/content' element={<WebContent />} /><Route path='/404' element={<NotFound />} /><Route path='*' element={<Navigate replace to='/404' />} /></Routes></div></React.Fragment>);}
}export default App;
6. 嵌套路由
假设 Linux
组件中有两个子模块 Homework
和 Terminal
,我们可以在 App
中创建嵌套路由:
import React, { Component } from 'react';
import NavBar from './navbar';
import Home from './home';
import Linux from './linux';
import Django from './django';
import Web from './web';
import WebContent from './webcontent';
import NotFound from './notfound';
import { Routes, Route, Navigate } from 'react-router-dom'class App extends Component {state = { } render() {return (<React.Fragment><NavBar /><div className='container'><Routes> // 一定要将路由包含在Routes里面,里面会有很多个Route<Route path='/' element={<Home />} /> // 如果链接为'/'就跳到Home组件<Route path='/linux' element={<Linux />}><Route path='homework' element={<h4>Homework</h4>} /><Route path='terminal' element={<h4>Terminal</h4>} /></Route><Route path='/django' element={<Django />} /><Route path='/web' element={<Web />} /><Route path='/web/content' element={<WebContent />} /><Route path='/404' element={<NotFound />} /><Route path='*' element={<Navigate replace to='/404' />} /></Routes></div></React.Fragment>);}
}export default App;
但是现在执行网页 /linux/homework
时不会渲染出子路由的内容,我们需要在父组件中添加 <Outlet />
组件,用来填充子组件的内容:
import React, { Component } from 'react';
import { Link, Outlet } from 'react-router-dom'class Linux extends Component {state = { } render() {return (<React.Fragment><h1>Linux</h1><hr /><ul className="nav justify-content-center"><li className="nav-item"><Link className="nav-link" to="/linux/homework">Homework</Link></li><li className="nav-item"><Link className="nav-link" to="/linux/terminal">Terminal</Link></li></ul><hr /><Outlet /></React.Fragment>);}
}export default Linux;
相关文章:
Web学习笔记-React(路由)
笔记内容转载自 AcWing 的 Web 应用课讲义,课程链接:AcWing Web 应用课。 CONTENTS 1. Web分类2. Route组件3. URL中传递参数4. Search Params传递参数5. 重定向6. 嵌套路由 本节内容是如何将页面和 URL 一一对应起来。 1. Web分类 Web 页面可以分为两…...

MySQL无法查看系统默认字符集以及校验规则
show variables like character_set_database; show variables like collation_database;这个错误信息表示MySQL在尝试访问performance_schema.session_variables表时,发现该表不存在。这个问题可能是由于MySQL的版本升级导致的。解决这个问题的一种方法是运行mysql…...

不负昭华,前程似锦,新一批研发效能认证证书颁发丨IDCF
亲爱的认证学员, 恭喜你成功获得由国家工业和信息化部教育与考试中心颁发的职业技术证书——《研发效能(DevOps)工程师国家职业技术认证》。你的努力和才华得到了官方的认可,这是你职业生涯中的一个重要的里程碑。 这个证书不仅代表着你的专业知识和技…...
深入理解ES6模块化:语法、特性与最佳实践
目录 一、前言 二、ES6模块化基础 1. 模块的定义与导出 2. 模块的导入与使用 3. 模块默认导出与命名导出 4. 模块的循环引用与解决方案 三、模块化语法进阶 1. 模块的命名导出与默认导出的混合使用 2. 模块的别名导出与导入 3. 命名空间的使用与作用 4. 动态导入模块…...

Matlab图像处理-HSI模型
HSI模型 HSI模型是从人的视觉系统出发,直接使用颜色三要素色调(Hue)、饱和度(Saturation)和亮度(Intensity)来描述颜色。 亮度是指人眼感知光线的明暗程度。光的能量越大,亮度就越大。 色调是颜色最重要的属性。 它决定了颜色的…...
【Springboot】Springboot如何优雅停机?K8S中Pod如何优雅停机?
什么是优雅停机: 就是对应用进程发送停止指令之后,执行的一系列保证应用正常关闭的操作。这些操作往往包括等待已有请求执行完成、关闭线程、关闭连接和释放资源等 就是对应用进程发送停止指令之后,能保证正在执行的业务操作不受影响&#x…...

伦敦银一手是多少?
伦敦银是以国际现货白银价格为跟踪对象的电子合约交易,无论投资者通过什么地方的平台进入市场,执行的都是统一国际的标准,一手标准的合约所代表的就是5000盎司的白银,如果以国内投资者比较熟悉的单位计算,那约相当于15…...

Language Adaptive Weight Generation for Multi-task Visual Grounding 论文阅读笔记
Language Adaptive Weight Generation for Multi-task Visual Grounding 论文阅读笔记 一、Abstract二、引言三、相关工作3.1 指代表达式理解3.2 指代表达式分割3.3 动态权重网络 四、方法4.1 总览4.2 语言自适应权重生成语言特征聚合权重生成 4.3 多任务头4.4 训练目标 五、实…...
面试算法4:只出现一次的数字
题目 输入一个整数数组,数组中只有一个数字出现了一次,而其他数字都出现了3次。请找出那个只出现一次的数字。例如,如果输入的数组为[0,1,0,1,0,1,100],则只…...
#与##的用法
# 作用: 左右加双引号,使其变成字符串 #的作用:是在形参左右各加双引号,使它变成字符串。#define STR(param) #paramchar *pStr STR(hello); // 展开后 char *pStr “hello”; ## 作用:胶水,使…...

Flutter的路由router-页面跳转
文章目录 概念介绍基本路由(Basic Routing)跳转到某个页面弹出页面 命名路由(Named Routing)第三方路由管理库(Third-Party Routing Libraries) Android原生的路由Intent-based Routing(基于Int…...

24v转5v稳压芯片-5A大电流输出ic
这款24V转5V5A汽车充电芯片具有以下特性和参数: - 宽输入电压范围:4.5V至36V - 最大输出电流:5.0A - 高达92%的转换效率 - 恒流/恒压模式控制 - 最大占空比100% - 可调输出电压 - 2%的输出电压精度 - 集成40mΩ高侧开关 - 集成18mΩ低侧开关 …...
Layui + Flask | 表单元素(组件篇)(06)
表单元素是输入框、选择框、复选框、开关、单选框等表单项组件,用于对表单域进行输入。layui 的表单元素对原生的表单元素进行了大幅的用着,有好看的 UI 同时又有非常方便操作的 API。 输入框 https://layui.dev/docs/2.8/form/input.html 输入框组件是对文本框 <input ty…...

Kakfa - Producer机制原理与调优
Producer是Kakfa模型中生产者组件,也就是Kafka架构中数据的生产来源,虽然其整体是比较简单的组件,但依然有很多细节需要细品一番。比如Kafka的Producer实现原理是什么,怎么发送的消息?IO通讯模型是什么?在实…...

基于图像形态学处理和边缘提取算法的路面裂痕检测matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 [Rr,Cc] size(Image1);% 获取 Image1 矩阵的大小(行数和列数) % 创…...

opencv 基础(持续更新中)
1 前言 https://www.couragesteak.com/ 2 安装 3 基础属性demo 打开一张图片: import cv2img cv2.imread(./girl.jpg)print(img.shape) # (1536, 1024, 3) 数组形状 print(type(img)) # numpy 数组 print(img) # 三维数组(彩色图片&am…...

科普现场!万博智云参加第五届张江汇智科普节
9月15日,第五届张江汇智科普节在汇智国际商业中心如期开展,展会中汇集了众多信息科技领域的新兴产品,展示内容主要分为国产替代和元宇宙场景展示两个方面。展现国产化最新科技成果,践行技术普惠理念,把高、精、专的技术…...
【记录】实现从Linux下载下载文件(文件导出功能)并记录过程产生的BUG问题。
前言 导出功能的实现,主要记录总结导出过程中出现的一些问题。 代码实现导出功能 public R templateDown(HttpServletResponse response) {String fileName "template.xlsx";// 清空responseresponse.reset();response.setCharacterEncoding("UTF…...
可扩展性表设计方案
文章目录 1 使用预留字段2 使用JSON字段3 使用单表继承4 构建属性表5 直接构建新表6 适当冗余 1 使用预留字段 在表设计初期,可以预留一些命名通用的备用字段,例如field1、field2、field3。当业务需要增加新字段时,就直接使用这些预留字段,无…...

Scotch: Combining SGX and SMM to Monitor Cloud Resource Usage【TEE的应用】
目录 摘要引言贡献 背景SMMXen Credit Scheduler与资源核算SGX 威胁模型Scheduler attacksResource interference attacksVM Escape attacks 架构Resource Accounting WorkflowCost of Accounting 具体的部署和评估见论文相关工作Resource Accounting基于SMM的方法基于SGX的系统…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...