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

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 题目分析与详解

一、题目简介&#xff1a; 二、通关思路&#xff1a; 1、首先查看页面源代码&#xff1a; 我们发现可以使用工具sqlmap来拿到flag&#xff0c;我们先尝试手动注入。 2、 打开靶机&#xff0c;映入眼帘的是登录界面&#xff0c;首先尝试万能密码能否破解。 username: 1 or 11…...

探索RedisJSON:将JSON数据力量带入Redis世界

探索RedisJSON&#xff1a;将JSON数据力量带入Redis世界 当我们谈论数据存储和查询时&#xff0c;Redis和JSON都是无法忽视的重要角色。Redis以其高效的键值存储、快速的读/写速度、以及丰富的数据结构赢得了开发者的喜爱。而JSON&#xff0c;作为一种轻量级的数据交换格式&am…...

【精通Spring】基于注解管理Bean

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…...

Python爬虫——Urllib库-3

目录 ajax的get请求 获取豆瓣电影第一页的数据并保存到本地 获取豆瓣电影前十页的数据 ajax的post请求 总结 ajax的get请求 获取豆瓣电影第一页的数据并保存到本地 首先可以在浏览器找到发送数据的接口 那么我们的url就可以在header中找到了 再加上UA这个header 进行请…...

JAVA工程师面试专题-《消息队列》篇

​​​​​​​ 1、为什么使用消息队列&#xff1f; 解耦、异步、削峰 2、消息队列有什么优缺点 优点&#xff1a;解耦、异步、削峰 缺点&#xff1a;系统可用性降低、系统复杂度提高、一致性问题 3、如何进⾏消息队列选型&#xff1f; Kafka&#xff1a; ○ 优点&…...

Unity3d Shader篇(十一)— 遮罩纹理

文章目录 前言一、什么是遮罩纹理&#xff1f;1. 遮罩纹理工作原理2. 遮罩纹理优缺点优点&#xff1a;缺点&#xff1a; 3. 遮罩纹理图 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数 三、效果四、总结 前言 在…...

测试开发(6)软件测试教程——自动化测试selenium(自动化测试介绍、如何实施、Selenium介绍 、Selenium相关的API)

接上次博客&#xff1a;测试开发&#xff08;5&#xff09;测试分类标准 &#xff1a;按测试对像划分、按是否查看代码划分、按开发阶段划分、按测试实施组织、按是否运行划分、按是否手工划分、按测试地域划分-CSDN博客 目录​​​​​​​ 什么是自动化测试 自动化测试介绍…...

【flink】Rocksdb TTL状态全量快照持续递增

flink作业中的MapState开启了TTL&#xff0c;并且使用rocksdb作为状态后端配置了全量快照方式&#xff08;同时启用全量快照清理&#xff09;&#xff0c;希望能维持一个平稳的运行状态&#xff0c;但是经观察后发现效果不达预期&#xff0c;不仅checkpoint size持续缓慢递增&a…...

[C++] 统计程序耗时

一、简介 本文介绍了两种在C代码中统计耗时的方法&#xff0c;第一种使用<time.h>头文件中的clock()函数记录时间戳&#xff0c;统计程序耗时。第二种使用<chrono>头文件中的std::chrono::high_resolution_clock()::now()函数&#xff0c;后者可以方便地统计不同时…...

Redis是单线程还是多线程?

单线程为什么这么快的原因&#xff1a; 后来引入了多线程是因为&#xff1a;...

【MySQL】MySQL数据管理——DDL数据操作语言(数据表)

目录 创建数据表语法列类型字段属性SQL示例创建学生表 查看表和查看表的定义表类型设置表的类型 面试题&#xff1a;MyISAM和InnoDB的区别设置表的字符集删除表语法示例 修改表修改表名语法示例 添加字段语法示例 修改字段语法示例 删除字段语法示例 数据完整性实体完整性域完整…...

Qt使用QSettings类来读写ini

在Qt中&#xff0c;可以使用QSettings类来读写ini文件。QSettings提供了一个简单的接口&#xff0c;用于访问和修改ini文件中的键值对。 下面是使用QSettings类来写入ini文件的示例代码&#xff1a; #include <QCoreApplication> #include <QSettings>int main(i…...

嵌入式软件bug从哪里来,到哪里去

摘要&#xff1a;软件从来不是一次就能完美的&#xff0c;需要以包容的眼光看待它的残缺。那问题究竟为何产生&#xff0c;如何去除呢&#xff1f; 1、软件问题从哪来 软件缺陷问题千千万万&#xff0c;主要是需求、实现、和运行环境三方面。 1.1 需求描述偏差 客户角度的描…...

去掉WordPress网页图片默认链接功能

既然是wordpress自动添加的&#xff0c;那么我们在上传图片到wordpress后台多媒体的时候&#xff0c;就可以手动改变链接指向或者删除掉&#xff0c;问题是每次都要这么做很麻烦&#xff0c;更别说有忘记的时候。一次性解决这个问题有两种方法&#xff0c;一种是No Image Link插…...

UE学习笔记--解决滚轮无法放大蓝图、Panel等

我们发现有时候创建蓝图之后&#xff0c;右上角的缩放是1&#xff1a;1 但是有时候我们可能需要放的更大一点。 发现一直用鼠标滚轮像上滚动&#xff0c;都没有效果。 好像最大只能 1&#xff1a;1. 那是因为 UE 做了限制。如果希望继续放大&#xff0c;我们可以按住 Ctrl 再去…...

GO结构体

1. 结构体 Go语言可以通过自定义的方式形成新的类型&#xff0c;结构体就是这些类型中的一种复合类型&#xff0c;结构体是由零个或多个任意类型的值聚合成的实体&#xff0c;每个值都可以称为结构体的成员。 结构体成员也可以称为“字段”&#xff0c;这些字段有以下特性&am…...

芯科科技为全球首批原生支持Matter-over-Thread的智能锁提供强大助力,推动Matter加速成为主流技术

智能锁领域的先锋企业U-tec和Nuki选择芯科科技解决方案&#xff0c;成为Matter-over-Thread应用的领先者 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#xff1a;SLAB&#xff09;今…...

面试数据库篇(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.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; 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 的集成与前…...