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. 更改动作类型action
      action = Action.Push;
      // 2. 创建一个新的location对象
      let location = createLocation(history.location, to, state);
      if (validateLocation) validateLocation(location, to);
      // 3. 当前索引idx
      index = 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. 更改动作类型action
      action = Action.Replace;
      // 2. 创建location对象
      let location = createLocation(history.location, to, state);
      if (validateLocation) validateLocation(location, to);
      // 3. 返回state状态对象中的idx,否则返回null
      index = getIndex();
      // 生成一个新对象,包含usr、key、idx:
      let historyState = getHistoryState(location, index);
      // 创建新的URL path
      let 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

核心容器中bean的操作

bean配置 bean基础配置 bean别名配置 **注意事项:**获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException(NoSuchBeanDefinitionException:No bean named ‘bookServiceImpl’ …

多GPU训练大型模型:资源分配与优化技巧 | 英伟达将推出面向中国的改良芯片HGX H20、L20 PCIe、L2 PCIe

★大模型、人工智能;数据并行;模型并行;流水线并行;混合精度训练、梯度累积;模型卸载CPU;重算;模型压缩;内存优化版优化器;Nvidia;A100;H100;A800…

Nutz框架如何自定义SQL?

Nutz框架基本的简单sql已经封装了,但是一些叫为复杂的sql需要手动去写,那如何实现像Mybatis那样通过配置文件编写呢?如有不明白详见官方文档:自定义 SQL - Nutzhttps://nutzam.com/core/dao/customized_sql.html#ndoc-4 一 新建…

Linux - Namespace

一、namespace 是什么? Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没…

Pikachu漏洞练习平台之XXE(XML外部实体注入)

目录 什么是 XML? 什么是DTD? 什么是XEE? 常见payload 什么是 XML? XML 指可扩展标记语言(EXtensible Markup Language); XML 不会做任何事情,而是用来结构化、存储以及传输信息…

java接收前端easyui datagrid传递的数组参数

这篇文章分享一下怎么在easyui的datagrid刷新表格时,在后端java代码中接收datagrid传递的数组参数。 数组来源于技能的tagbox(标签框),tagbox和combobox的区别是tagbox可以选择多项。 标签框渲染的代码为 $("#skill_ids"…

确保人工智能的公平性:生成无偏差综合数据的策略

一、介绍 合成数据生成涉及创建密切模仿现实世界数据但不包含任何实际个人信息的人工数据,从而保护隐私和机密性。然而,至关重要的是,这些数据必须以公平、公正的方式生成,以防止人工智能应用中现有的偏见长期存在或扩大。 在数据…

12-2- DCGAN -简单网络-卷积网络

功能 随机噪声→生成器→MINIST图像。 训练方法 1 判别器的训练,首先固定生成器参数不变,其次判别器应当将真实图像判别为1,生成图像判别为0 loss=loss(real_out, 1)+loss(fake_out, 0) 2 生成器的训练,首先固定判别器参数不变,其次判别器应当将生成图像判别为1 loss =…

YOLOv5独家原创改进:最新原创WIoU_NMS改进点,改进有效可以直接当做自己的原创改进点来写,提升网络模型性能精度

💡该教程为属于《芒果书》📚系列,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀 💡本篇文章为YOLOv5独家原创改进:独家首发最新原创WIoU_NMS改进点,改进有效可以直接当做自己的原创改进点来写,提升网络模型性能精度。 💡对自己数据集改进有效…

TensorFlow案例学习:图片风格迁移

准备 官方教程: 任意风格的快速风格转换 模型下载地址: https://tfhub.dev/google/magenta/arbitrary-image-stylization-v1-256/2 学习 加载要处理的内容图片和风格图片 # 用于将图像裁剪为方形def crop_center(image):# 图片原始形状shape image…

微信小程序相机相册授权后,需要重启客户端才能正常调用相机,无法调起窗口选择图片,无反应解决方案

最近微信小程序很多功能突然不能使用,本篇针对无法调起相册进行说明 解决方案 检查小程序隐私协议是否配置,操作步骤这里不在详细说明,点击教程按照上面的教程,找到入口后点击完善或者更新 选择选中的照片或视频这个权限要申请 之…

OpenCV入门4——实现图形的绘制

文章目录 OpenCV绘制直线OpenCV绘制矩形和圆画矩形画圆 OpenCV椭圆的绘制OpenCV绘制多边形OpenCV绘制文本实现鼠标绘制基本图形 OpenCV绘制直线 # -*- coding: utf-8 -*- import cv2 import numpy as npimg np.zeros((480, 640, 3), np.uint8) # 坐标点为(x, y) cv2.line(img,…

Unity | 运行时显示调试信息

「公众号:游戏开发手记」 1 简介 在 Unity 编辑器中,我们可以通过点击 Stats 按钮来查看 Statistics 面板,这个面板显示了许多关于游戏渲染的信息,如每帧的渲染时间、Tris 和 Verts 的数量、SetPass Calls 的数量等。但在其他运…

Java设计模式-结构型模式-装饰模式

装饰模式 装饰模式角色案例装饰模式与静态代理的区别 装饰模式 允许向一个现有的对象动态地添加新的功能,同时不改变其结构。它是继承的一种替代方案,可以动态地扩展对象。有点像静态代理 角色 装饰者模式有四种角色 抽象被装饰者,被装饰者…

基于单片机的自动循迹小车(论文+源码)

1.系统设计 此次基于单片机的自动循迹小车的设计系统,结合循迹模块来共同完成本次设计,实现小车的循迹功能,其其整体框架如图2.1所示。其中,采用STC89C52单片机来作为核心控制器,负责将各个传感器等模块链接起来&…

23款奔驰GLC260L升级小柏林音响 全新15个扬声器

2023年款奔驰GLC260 GLC300升级小柏林之声 3D音效系统 升级小柏林之声音响之后,全车一共有15个喇叭,1台功放,每一首音乐都能在车内掀起激情的音浪,感受纯粹的音乐享受,低频震撼澎湃,让你的心跳与音乐完美契…

js的数组

js js 的数组数组是什么为什么要使用数组数组的简单使用数组是按照顺序保存的,所以每个数据都有自己的编号数组的取值方法遍历数组数组的元素求和数组的最大值和最小值数组的增删改查操作数组的增加数组的筛选数组的删除 案例: 九九乘法表 数组是什么 数…

内置升压的单声道D类音频功率放大器:HT81293

HT81293是一款内置升压的单声道D类音频功率放大器,由锂电池供电时, THDN10%, 能连续输出18W功率(4Ω负载)。 HT81293A内置可动态调节的升压,可以提供一个适应不同输出功率的电压给D类功放,其可大…

Swagger使用

Swagger使用 1. Swagger UI 按以下步骤配置&#xff0c;项目启动后访问&#xff1a; http://localhost:8080/swagger-ui.html 1.1 添加依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><ve…

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

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