react 路由的基本原理及实现
1. react 路由原理
不同路径渲染不同的组件
有两种实现方式
● HasRouter 利用hash实现路由切换
● BrowserRouter 实现h5 API实现路由切换
1. 1 HasRouter
利用hash 实现路由切换

1.2 BrowserRouter
利用h5 Api实现路由的切换
1.2.1 history
- HTML5规范给我们提供了一个history接口
- HTML5 HIstory API包含两个方法:history.pushState()和history.replaceState(),和一个事件
window.onpopstate pushState
1.2.1.1 history.pushState(stateObject,title,url)
● 第一个参数用于存储该url对应的状态对象,该对象可在onpopstate事件中获取,也可在history对象中获取
● 第二个参数是标题,目前浏览器并未实现
● 第三个参数是设定的url
pushState函数向浏览器的历史堆栈中压入一个url为设定值的记录,并改变历史堆栈的当前指针至栈顶
1.2.1.2 replaceState
● 该接口与pushState参数相同,含义 也相同
● 唯一的区别在于replaceState是替换浏览器历史栈中的当前历史记录为设定的url
● 需要注意的是replaceState 不会改动浏览器历史堆栈的当前指针
1.2.1.3 onpopstate
● 该事件是window属性
● 该事件会在调用浏览器的前进,后退以及在执行history.forward,history.back 和history.go 的时候触发。因为这些操作有一个共性,即修改了历史堆栈的当前指针
● 在不改变document 的前提下,一旦触发当前指针改变则会触发onpopstate事件
2 实现基本路由
2.1 HashRouter 基本用法及实现
import React from 'react';
import { Router } from '../react-router';
import { createHashHistory } from '../history';
class HashRouter extends React.Component {constructor(props) {super(props);this.history = createHashHistory(props)}render() {return (<Router history={this.history}>{this.props.children}</Router>)}
}
export default HashRouter;
history 下的 createHashHistory.js
/*** 工厂方法,用来返回一个历史对象*/
function createHashHistory(props) {let stack = [];//模拟一个历史条目栈,这里放的都是每一次的locationlet index = -1;//模拟一个当前索引let action = 'POP';//动作let state;//当前状态let listeners = [];//监听函数的数组let currentMessage;let userConfirm = props.getUserConfirmation?props.getUserConfirmation():window.confirm;function go(n) {//go是在历史条目中跳前跳后,条目数不会发生改变action = 'POP';index += n;if(index <0){index=0;}else if(index >=stack.length){index=stack.length-1;}let nextLocation = stack[index];state=nextLocation.state;window.location.hash = nextLocation.pathname;//用新的路径名改变当前的hash值}function goForward() {go(1)}function goBack() {go(-1)}let listener = ()=>{let pathname = window.location.hash.slice(1);// /users#/api /apiObject.assign(history,{action,location:{pathname,state}}); if(action === 'PUSH'){stack[++index]=history.location;//1 2 3 6 5 //stack.push(history.location);}listeners.forEach(listener=>listener(history.location));}window.addEventListener('hashchange',listener);//to={pathname:'',state:{}}function push(to,nextState){action = 'PUSH';let pathname;if(typeof to === 'object'){state = to.state;pathname = to.pathname;}else {pathname = to;state = nextState;}if(currentMessage){let message = currentMessage({pathname});let allow = userConfirm(message);if(!allow) return;}window.location.hash = pathname;}function listen(listener) {listeners.push(listener);return function () {//取消监听函数,如果调它的放会把此监听函数从数组中删除listeners = listeners.filter(l => l !== listener);}}function block(newMessage){currentMessage = newMessage;return ()=>{currentMessage=null;}}const history = {action,//对history执行的动作push,go,goBack,goForward,listen,location:{pathname:window.location.hash.slice(1),state:undefined},block}if(window.location.hash){action = 'PUSH';listener();}else{window.location.hash='/';}return history;
}export default createHashHistory;
2.2 BrowserRouter基本用法及实现
import React from 'react';
import { Router } from '../react-router';
import { createBrowserHistory } from '../history';
class BrowserRouter extends React.Component {constructor(props) {super(props);this.history = createBrowserHistory(props)}render() {return (<Router history={this.history}>{this.props.children}</Router>)}
}
export default BrowserRouter;
history 下的 createBrowserHistory.js
/*** 工厂方法,用来返回一个历史对象*/
function createBrowserHistory(props){let globalHistory = window.history;let listeners = [];let currentMessage;let userConfirm = props.getUserConfirmation?props.getUserConfirmation():window.confirm;function go(n){globalHistory.go(n);}function goForward(){globalHistory.goForward();}function goBack(){globalHistory.goBack();}function listen(listener){listeners.push(listener);return function(){//取消监听函数,如果调它的放会把此监听函数从数组中删除listeners = listeners.filter(l=>l!==listener);}}window.addEventListener('popstate',(event)=>{//push入栈 pop类似于出栈setState({action:'POP',location:{state:event.state,pathname:window.location.pathname}});});function setState(newState){Object.assign(history,newState);history.length = globalHistory.length;listeners.forEach(listener=>listener(history.location));}/*** push方法* @param {*} path 跳转的路径* @param {*} state 跳转的状态*/function push(to,nextState){//对标history pushStateconst action = 'PUSH';let pathname;let state;if(typeof to === 'object'){state = to.state;pathname = to.pathname;}else {pathname = to;state = nextState;}if(currentMessage){let message = currentMessage({pathname});let allow = userConfirm(message);if(!allow) return;}globalHistory.pushState(state,null,pathname);let location = {state,pathname};setState({action,location});}function block(newMessage){currentMessage = newMessage;return ()=>{currentMessage=null;}
}const history = {action:'POP',//对history执行的动作push,go,goBack,goForward,listen,location:{pathname:window.location.pathname,state:globalHistory.state},block}return history;
}export default createBrowserHistory;
相关文章:
react 路由的基本原理及实现
1. react 路由原理 不同路径渲染不同的组件 有两种实现方式 ● HasRouter 利用hash实现路由切换 ● BrowserRouter 实现h5 API实现路由切换 1. 1 HasRouter 利用hash 实现路由切换 1.2 BrowserRouter 利用h5 Api实现路由的切换 1.2.1 history HTML5规范给我们提供了一个…...
[极客大挑战 2019]LoveSQL1 题目分析与详解
一、题目简介: 二、通关思路: 1、首先查看页面源代码: 我们发现可以使用工具sqlmap来拿到flag,我们先尝试手动注入。 2、 打开靶机,映入眼帘的是登录界面,首先尝试万能密码能否破解。 username: 1 or 11…...
探索RedisJSON:将JSON数据力量带入Redis世界
探索RedisJSON:将JSON数据力量带入Redis世界 当我们谈论数据存储和查询时,Redis和JSON都是无法忽视的重要角色。Redis以其高效的键值存储、快速的读/写速度、以及丰富的数据结构赢得了开发者的喜爱。而JSON,作为一种轻量级的数据交换格式&am…...
【精通Spring】基于注解管理Bean
个人名片: 🐼作者简介:一名大三在校生,喜欢AI编程🎋 🐻❄️个人主页🥇:落798. 🐼个人WeChat:hmmwx53 🕊️系列专栏:🖼️…...
Python爬虫——Urllib库-3
目录 ajax的get请求 获取豆瓣电影第一页的数据并保存到本地 获取豆瓣电影前十页的数据 ajax的post请求 总结 ajax的get请求 获取豆瓣电影第一页的数据并保存到本地 首先可以在浏览器找到发送数据的接口 那么我们的url就可以在header中找到了 再加上UA这个header 进行请…...
JAVA工程师面试专题-《消息队列》篇
1、为什么使用消息队列? 解耦、异步、削峰 2、消息队列有什么优缺点 优点:解耦、异步、削峰 缺点:系统可用性降低、系统复杂度提高、一致性问题 3、如何进⾏消息队列选型? Kafka: ○ 优点&…...
Unity3d Shader篇(十一)— 遮罩纹理
文章目录 前言一、什么是遮罩纹理?1. 遮罩纹理工作原理2. 遮罩纹理优缺点优点:缺点: 3. 遮罩纹理图 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数 三、效果四、总结 前言 在…...
测试开发(6)软件测试教程——自动化测试selenium(自动化测试介绍、如何实施、Selenium介绍 、Selenium相关的API)
接上次博客:测试开发(5)测试分类标准 :按测试对像划分、按是否查看代码划分、按开发阶段划分、按测试实施组织、按是否运行划分、按是否手工划分、按测试地域划分-CSDN博客 目录 什么是自动化测试 自动化测试介绍…...
【flink】Rocksdb TTL状态全量快照持续递增
flink作业中的MapState开启了TTL,并且使用rocksdb作为状态后端配置了全量快照方式(同时启用全量快照清理),希望能维持一个平稳的运行状态,但是经观察后发现效果不达预期,不仅checkpoint size持续缓慢递增&a…...
[C++] 统计程序耗时
一、简介 本文介绍了两种在C代码中统计耗时的方法,第一种使用<time.h>头文件中的clock()函数记录时间戳,统计程序耗时。第二种使用<chrono>头文件中的std::chrono::high_resolution_clock()::now()函数,后者可以方便地统计不同时…...
Redis是单线程还是多线程?
单线程为什么这么快的原因: 后来引入了多线程是因为:...
【MySQL】MySQL数据管理——DDL数据操作语言(数据表)
目录 创建数据表语法列类型字段属性SQL示例创建学生表 查看表和查看表的定义表类型设置表的类型 面试题:MyISAM和InnoDB的区别设置表的字符集删除表语法示例 修改表修改表名语法示例 添加字段语法示例 修改字段语法示例 删除字段语法示例 数据完整性实体完整性域完整…...
Qt使用QSettings类来读写ini
在Qt中,可以使用QSettings类来读写ini文件。QSettings提供了一个简单的接口,用于访问和修改ini文件中的键值对。 下面是使用QSettings类来写入ini文件的示例代码: #include <QCoreApplication> #include <QSettings>int main(i…...
嵌入式软件bug从哪里来,到哪里去
摘要:软件从来不是一次就能完美的,需要以包容的眼光看待它的残缺。那问题究竟为何产生,如何去除呢? 1、软件问题从哪来 软件缺陷问题千千万万,主要是需求、实现、和运行环境三方面。 1.1 需求描述偏差 客户角度的描…...
去掉WordPress网页图片默认链接功能
既然是wordpress自动添加的,那么我们在上传图片到wordpress后台多媒体的时候,就可以手动改变链接指向或者删除掉,问题是每次都要这么做很麻烦,更别说有忘记的时候。一次性解决这个问题有两种方法,一种是No Image Link插…...
UE学习笔记--解决滚轮无法放大蓝图、Panel等
我们发现有时候创建蓝图之后,右上角的缩放是1:1 但是有时候我们可能需要放的更大一点。 发现一直用鼠标滚轮像上滚动,都没有效果。 好像最大只能 1:1. 那是因为 UE 做了限制。如果希望继续放大,我们可以按住 Ctrl 再去…...
GO结构体
1. 结构体 Go语言可以通过自定义的方式形成新的类型,结构体就是这些类型中的一种复合类型,结构体是由零个或多个任意类型的值聚合成的实体,每个值都可以称为结构体的成员。 结构体成员也可以称为“字段”,这些字段有以下特性&am…...
芯科科技为全球首批原生支持Matter-over-Thread的智能锁提供强大助力,推动Matter加速成为主流技术
智能锁领域的先锋企业U-tec和Nuki选择芯科科技解决方案,成为Matter-over-Thread应用的领先者 致力于以安全、智能无线连接技术,建立更互联世界的全球领导厂商Silicon Labs(亦称“芯科科技”,NASDAQ:SLAB)今…...
面试数据库篇(mysql)- 06覆盖索引
原理 覆盖索引是指查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到 。 id name gender createdate 2 Arm...
[伴学笔记]01-操作系统概述 [南京大学2024操作系统]
文章目录 前言jyy:01-操作系统概述 [南京大学2024操作系统]为什么要学操作系统?学习操作系统能得到什么? 什么是操作系统?想要明白什么是操作系统:时间线:1940s1950s-1960s1960-1970s年代. 信息来源: 前言 督促自己,同时分享所得,阅读完本篇大约需要10分钟,希望为朋友的技术…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
