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

react-router/react-router-dom

最近看了react-router 源码,对react-router有了更深的理解,下面写点东西备忘:
react-router-dom 是对react-router 的扩展,而两者实现路由跳转的本质依赖于一个history 插件。
此history 插件 是对浏览器原生 history 的封装。

BrowserHistory

1.push

 function push(path, state) {
...globalHistory.pushState({key: key,state: state}, null, href);
...
}

2.replace

function replace(path, state) {
...globalHistory.replaceState({key: key,state: state}, null, href);
...
}

3.Listeners

var PopStateEvent = 'popstate';
var HashChangeEvent = 'hashchange';
function checkDOMListeners(delta) {listenerCount += delta;if (listenerCount === 1 && delta === 1) {window.addEventListener(PopStateEvent, handlePopState);if (needsHashChangeListener) window.addEventListener(HashChangeEvent, handleHashChange);} else if (listenerCount === 0) {window.removeEventListener(PopStateEvent, handlePopState);if (needsHashChangeListener) window.removeEventListener(HashChangeEvent, handleHashChange);}}

总结 :history router 基于 html5 新增的 history API,pushState, replaceState,其用法如下:
history.pushState(state, title, url);
history.replaceState(state, title, url);
即:跳转到 url 路径(与当前页面处在同一个域 ,形如一个网站的
location.pathname 部分),指定新页面的标题 title,但是浏览器目前都忽略这个值,因此这里一般使用 null,state 为关联新地址的状态对象(刷新页面并不会丢失)。二者的区别就是,pushState 会增加一条浏览器记录,而replaceState 会替换当前历史记录。相同点是,均不会刷新当前页面,也不会发生真正的跳转,而是仅仅改变了地址栏的 URL(history、location 对象)。
同时 history router 通过 popstate 来监听变化。

hash router

1.push

function pushHashPath(path) {window.location.hash = path;
}
  1. replace
function replaceHashPath(path) {window.location.replace(stripHash(window.location.href) + '#' + path);
}
  1. Listeners
var HashChangeEvent$1 = 'hashchange';
function checkDOMListeners(delta) {listenerCount += delta;if (listenerCount === 1 && delta === 1) {window.addEventListener(HashChangeEvent$1, handleHashChange);} else if (listenerCount === 0) {window.removeEventListener(HashChangeEvent$1, handleHashChange);}}

总结: hash router 基于 location.hash = pathString 来更新网站路径。pathString 代表网址中 # 号后面直到 search 的部分。与 history 不同的是,如果两次赋值一样的时候,并不会触发 hashchange 和 popstate 方法。同时浏览器通过 hashchange 事件来监听路由变化。

MemoryHistory

在非浏览器环境,使用抽象路由实现导航的记录功能MemoryHistory,即在内存中保存的一个创建的虚拟路由对象。

getUserConfirmation

getUserConfirmation 约等于 vue-router 中路由守卫,它是在路由跳转时的钩子函数,当传入它时可以在getUserConfirmation 内控制时都进行路由跳转。
getUserConfirmation 的用法如下

<BrowserRoutergetUserConfirmation={(message, callback) => {// this is the default behaviorconst allowTransition = window.confirm(message);callback(allowTransition);}}
/>

即 当callback(true) 会跳转,callback(false) 不会跳转,那么我们看一下 在触发路由跳转时 做了什么操作

 function confirmTransitionTo(location, action, getUserConfirmation, callback) {// TODO: If another transition starts while we're still confirming// the previous one, we may end up in a weird state. Figure out the// best way to handle this.if (prompt != null) {var result = typeof prompt === 'function' ? prompt(location, action) : prompt;if (typeof result === 'string') {if (typeof getUserConfirmation === 'function') {getUserConfirmation(result, callback);     // 重点在这里} else {warning(false, 'A history needs a getUserConfirmation function in order to use a prompt message');callback(true);}} else {// Return false from a transition hook to cancel the transition.callback(result !== false);}} else {callback(true);}}

在进行跳转时会调用getUserConfirmation 传入result, callback
callback 什么函数呢? 以createBrowserHistory push 中的为例:

 function push(path, state) {warning(!(typeof path === 'object' && path.state !== undefined && state !== undefined), 'You should avoid providing a 2nd state argument to push when the 1st ' + 'argument is a location-like object that already has state; it is ignored');var action = 'PUSH';var location = createLocation(path, state, createKey(), history.location);transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {if (!ok) return;  // 传入非 true 则不进行任何操作var href = createHref(location);var key = location.key,state = location.state;if (canUseHistory) {globalHistory.pushState({key: key,state: state}, null, href);if (forceRefresh) {window.location.href = href;} else {var prevIndex = allKeys.indexOf(history.location.key);var nextKeys = allKeys.slice(0, prevIndex + 1);nextKeys.push(location.key);allKeys = nextKeys;setState({action: action,location: location});}} else {warning(state === undefined, 'Browser history cannot push state in browsers that do not support HTML5 history');window.location.href = href;}});}

可见 callback 中只有传入true 才可以执行下一步,由此我们可以通过 getUserConfirmation 实现路由拦截。

最后编辑于:2025-06-15 11:02:55


喜欢的朋友记得点赞、收藏、关注哦!!!

http://www.dtcms.com/a/319377.html

相关文章:

  • 对话访谈|盘古信息×冠捷科技:全球制造标杆的智能化密码
  • 鸿蒙类型转化Json转map
  • 【实录】NestJS 中的 IoC
  • 动力电池点焊机:效率质量双提升,驱动新能源制造升级
  • 中小制造企业数字化转型的可持续发展:IT架构演进与管理模式迭代
  • [盛最多水的容器]
  • WPS定制设置成绿色软件
  • Go语言Ebiten坦克大战
  • ADC常用库函数(STC8系列)
  • 现代制冷系统核心技术解析:从四大件到智能控制的关键突破
  • 客户管理系统的详细项目框架结构
  • 从房地产企业运作观企业能力建设
  • (第八期)VS Code 网页开发入门指南:从零开始掌握前端开发工具
  • Leetcode——菜鸟笔记2(移动0)
  • 92. 反转链表 II
  • 【实时Linux实战系列】实时分布式计算架构的实现
  • DataEase官方出品丨SQLBot:基于大模型和RAG的智能问数系统
  • 机柜指示灯识别误报率↓85%:陌讯多模态融合算法实战解析
  • Linux 内核:节点创建汇总
  • NFS 服务器
  • 【运维进阶】NFS 服务器
  • 16.Home-懒加载指令优化
  • .NET 10 新增功能系列文章5——C# 14 中的新增功能
  • latex in overleaf快速通关论文排版
  • E频段无线射频链路为5G网络提供高容量回程解决方案 — 第一部分
  • Linux(17)——Linux进程信号(下)
  • 【RabbitMQ面试精讲 Day 14】Federation插件与数据同步
  • 剑指offer第2版——面试题1:赋值运算符函数
  • 《常见高频算法题 Java 解法实战精讲(2):堆栈与递归》
  • 【RabbitMQ面试精讲 Day 15】RabbitMQ故障转移与数据恢复