React-Router源码分析-History库

history源码


history 在 v5 之前使用单独的包, v6 之后再 router 包中单独实现。

history源码

Action


路由切换的动作类型,包含三种类型:

  • POP
  • REPLACE
  • PUSH

Action 枚举:

export enum Action {Pop = "POP",Push = "PUSH",Replace = "REPLACE",
}

关于三种动作类型意思,可以进入Actions了解。

createLocation(current, to , state, key)


创建一个含有唯一值key的location对象。

当前方法是一个公共方法,在createBrowserHistory/createHashHistory/createMemoryHistory中都使用其创建location对象。

如果你需要更深层次了解,请进入createLocation。

getUrlBasedHistory(getLocation, createHref, validateLocation, options)


createBrowserHistory/createHashHistory函数都基于getUrlBasedHistory,执行getUrlBasedHistory后,会返回一个history对象。

History库


history库文件暴露出createMemoryHistory、createBrowserHistory、createHashHistory三个方法,每种方法作用不一样。

  • createMemoryHistory:用于非 dom 环境,react-native 和测试环境

  • createBrowserHistory/createHashHistory:用于浏览器环境,createBrowserHistory对应于history路由模式,而createHashHistory应用于hash模式路由,两者方法的底层都是利用了HTML5 history API方法实现(即监听popstate事件及replaceState、pushState无刷新更改location URL)

createBrowserHistory/createHashHistory函数都基于getUrlBasedHistory ,提供不同的:

  • getLocation
  • createHref
  • validateLocation
  • options

属性实现不同的 history 对象

执行步骤
history-library history-library

history对象属性和方法


  1. action

    当前location对象变化的动作类型,关于三种动作类型意思,可以进入Actions了解。

  2. location

    返回当前的location对象。

    底层:getLocation => createLocation()

    具体内容可访问createLocation。

  3. listen(fn: Listener)

    在createBrowserHistory函数(此刻以此举例)中,会有一个listener变量来接收传入的监听回调函数fn。

    注意:一个history中,有且仅有一个活跃的listen监听函数,否则会抛出一个异常。

    如果你想要继续传入一个监听回调事件,你可以先执行history.listen(fn)的返回值(作用:清除监听事件),再传入fn。

    监听location变化的函数,传入一个回调函数fn,并将代表location变化的一个update对象传入回调函数中。


    内部逻辑:

    (1) 创建一个popstate监听事件,回调函数handlePop

    (2) 将listener = fn;

    (3)返回一个函数(作用:执行这个函数,可以取消当前的listener);

    源码:

    listen(fn: Listener) {if (listener) {throw new Error("A history only accepts one active listener");}window.addEventListener(PopStateEventType, handlePop);listener = fn;return () => {window.removeEventListener(PopStateEventType, handlePop);listener = null;};
    },
    

    Listener interface

     export interface Listener {(update: Update): void;}
    

    Update interface

     export interface Update {action: Action; // 动作类型location: Location; // 新的location对象delta: number | null; // 目的location对象(也可以理解为新的location对象)与之前的location,在history栈中之间的增量}
    
  • createHref(to)

    创建地址

    createBrowserHistory

    如果to是一个string,返回to,否则createPath(to),如果想了解createPath,请访问createPath。

    内部调用: createBrowserHref(window, to)

    function createBrowserHref(window: Window, to: To) {return typeof to === "string" ? to : createPath(to);
    }
    

    createHashHistory

    如果to是一个string,返回to,否则createPath(to),如果想了解createPath,请访问createPath。

    内部调用: createBrowserHref(window, to)

    function createHashHref(window: Window, to: To) {let base = window.document.querySelector("base");let href = "";if (base && base.getAttribute("href")) {let url = window.location.href;let hashIndex = url.indexOf("#");href = hashIndex === -1 ? url : url.slice(0, hashIndex);}return href + "#" + (typeof to === "string" ? to : createPath(to));
    }
    
  • go(n)

    指定跳转地址,调用和HTML5 history api的go方法一样, 如果想了解原生的history,请访问history。

  • push

    添加一个新的历史记录

    function push(to: To, state?: any) {// 1. 更改动作类型actionaction = Action.Push;// 2. 创建一个新的location对象let location = createLocation(history.location, to, state);if (validateLocation) validateLocation(location, to);// 3. 当前索引idxindex = getIndex() + 1;// 4. state状态对象{ idx: index,usr: state, key: 唯一的key值 }let historyState = getHistoryState(location, index);let url = history.createHref(location);// try...catch because iOS limits us to 100 pushState calls :/try {globalHistory.pushState(historyState, "", url);} catch (error) {if (error instanceof DOMException && error.name === "DataCloneError") {throw error;}window.location.assign(url);}if (v5Compat && listener) {// 执行location变化的监听回调事件listener--调用history.listen中传入的事件listener({ action, location: history.location, delta: 1 });}
    }
    
  • replace

    替换当前的历史记录

    function replace(to: To, state?: any) {// 1. 更改动作类型actionaction = Action.Replace;// 2. 创建location对象let location = createLocation(history.location, to, state);if (validateLocation) validateLocation(location, to);// 3. 返回state状态对象中的idx,否则返回nullindex = getIndex();// 生成一个新对象,包含usr、key、idx:let historyState = getHistoryState(location, index);// 创建新的URL pathlet url = history.createHref(location);// history API中的replaceState替换当前的历史记录globalHistory.replaceState(historyState, "", url);if (v5Compat && listener) {listener({ action, location: history.location, delta: 0 });}
    }
    

更多内容,欢迎访问https://www.wangyuegyq.top

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/144286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OCR转换技巧:如何避免图片转Word时出现多余的换行?

在将图片中的文字识别转换为Word文档时,我们很多时候时会遇到识别内容的一个自然段还没结束就换行的问题,这些就是我们常说的多余换行的问题。为什么会产生这个问题呢?主要是由于OCR返回的识别结果是按图片上的文字换行而换行,而不…

算法通关村第十一关|白银|位运算高频算法题【持续更新】

1.位移 1.1 位1的个数 原题:力扣191. 挨个判断是不是 1 的话需要对整个长度进行遍历,但是采用技巧可以只寻找为 1 的位,然后将其数量记录下来。 public int hammingWeight(int n) {int count 0;while (n ! 0) {n n & (n - 1);count…

高并发架构设计(三大利器:缓存、限流和降级)

引言 高并发背景 互联网行业迅速发展,用户量剧增,系统面临巨大的并发请求压力。 软件系统有三个追求:高性能、高并发、高可用,俗称三高。三者既有区别也有联系,门门道道很多,全面讨论需要三天三夜&#…

web3资讯及远程工作

各位如果想了解区块链相关的消息可以通过如下网址了解,里面还会有相关职位招聘(包括远程工作),还可以在里面进行发帖,进入即可获得1000积分,后期可以兑换一些礼品Cryptosquare

如何检查 Docker 和 Kubernetes 是否可以访问外部网络,特别是用于拉取镜像的仓库?

要检查 Docker 和 Kubernetes 是否可以访问外部网络,尤其是用于拉取容器镜像的仓库,您可以按照以下步骤进行: 1. 检查节点的网络连接 首先,您需要确保 Kubernetes 节点能够访问外部网络。这可以通过在节点上执行 ping 命令来测试…

git 简单入门

git init touch test.txt git add test.txt git commit -m 初始化 仓库 git log //查找日志 git checkout -b dev //创建并切换dev分支 git branch // 查找分支 此时有master 和 dev分支, 此时在dev分支 dev分支也有test.txt文件 vim test.txt //写入dev …

2023 年 数维杯(B题)国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时,你是否曾经感到茫然无措?作为2021年美国大学生数学建模比赛的O奖得主,我为大家提供了一套优秀的解题思路,让你轻松应对各种难题。 让我们来看看数维杯(B题)! …

LeetCode617. Merge Two Binary Trees

文章目录 一、题目二、题解 一、题目 You are given two binary trees root1 and root2. Imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not. You need to merge the two trees into a new b…

一文看懂Spark中Cache和CheckPoint的区别

目录 循循渐进理解使用Cache或者PersistCheckPoint缓存和CheckPoint的区别 循循渐进理解 wc.txt数据 hello java spark hadoop flume kafka hbase kafka flume hadoop看下面代码会打印多少条-------------------------(RDD2) import org.apache.spark.rdd.RDD import org.ap…

PHP调用调用API接口的方法及实现

随着互联网、云计算和大数据时代的到来,越来越多的应用程序需要调用第三方的API接口来获取数据,实现数据互通和协同工作。PHP作为一种常用的服务器端语言,也可以通过调用API接口来实现不同系统的数据交互和整合。本文将介绍PHP调用电商API接口…

Jmeter- Beanshell语法和常用内置对象(网络整理)

在利用jmeter进行接口测试或者性能测试的时候,我们需要处理一些复杂的请求,此时就需要利用beanshell脚本了,BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法,所以它和java是可以无缝衔接的。beans…

RK3588平台开发系列讲解(摄像头篇)USB摄像头驱动分析

🚀返回专栏总目录 文章目录 一. USB摄像头基本知识1.1 内部逻辑结构1.2 描述符实例解析二. UVC驱动框架2.1、设备枚举过程2.2、数据传输过程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 USB摄像头驱动位于 drivers\media\usb\uvc\uvc_driver.c ,我们本篇重点看下…

MacOS设置JAVA_HOME环境变量

首先先查看一下,系统当前使用的java是谁,可以使用/usr/libexec/java_home命令 % /usr/libexec/java_home /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home检查一下这个路径下的文件,发现这是一个jre的目录。加上-V参数看…

Redis篇---第二篇

系列文章目录 文章目录 系列文章目录一、为什么 使用 Redis 而不是用 Memcache 呢?二、为什么 Redis 单线程模型效率也能那么高?三、说说 Redis 的线程模型一、为什么 使用 Redis 而不是用 Memcache 呢? 这时候肯定想到的就是做一个 Memcache 与 Redis 区别。 Redis 和 Mem…

移动机器人路径规划(二)--- 图搜索基础,Dijkstra,A*,JPS

目录 1 图搜索基础 1.1 机器人规划的配置空间 Configuration Space 1.2 图搜索算法的基本概念 1.3 启发式的搜索算法 Heuristic search 2 A* Dijkstra算法 2.1 Dijkstra算法 2.2 A*&&Weighted A*算法 2.3 A* 算法的工程实践中的应用 3 JPS 1 图搜索基础 1.1…

AD教程 (十六)常用PCB封装的直接调用

AD教程 (十六)常用PCB封装的直接调用 打开已经做好的PCB文件 点击设计,生成PCB库,会自动把PCB里所用到的所有封装,全部自动生成 CtrlA 将所有元器件的封装全部选中(或者只选中所需要的)&#x…

TikTok与心灵成长:娱乐与启发并重

社交媒体已成为我们生活的一部分,其中TikTok以其短视频内容和创新性而闻名。然而,TikTok不仅仅是一个娱乐平台,它还具有潜力成为心灵成长的有力工具。本文将探讨TikTok如何在娱乐与启发之间取得平衡,以促进心灵成长和积极影响。 娱…

利用curl测试WSS连接的建立

记录下: curl -vvv --include --no-buffer \ --header "Connection: Upgrade" \ --header "Upgrade: websocket" \ --header "Host: transcribestreaming.us-east-1.amazonaws.com:8443" \ --header "Origin: http://localhost…

IntelliJ IDEA启动一个普通的java web项目的配置

原创/朱季谦 这是我很久以前刚开始用IntelliJ IDEA时记录的笔记,应该是五年前的一篇笔记了。正好赶上最近离职了,可以有比较多的时间把以前的记录整理一下,可以让刚接触到IntelliJ IDEA的童鞋学习如何在IntelliJ IDEA引入一个单机版的jar形式…

蓝桥杯 冒泡排序

冒泡排序的思想 冒泡排序的思想是每次将最大的一下一下移动到最右边,然后将最右边这个确定下来。 再来确定第二大的,再确定第三大的… 对于数组a[n],具体来说,每次确定操作就是从左往右扫描,如果a[i]>a[i1],我们将…