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

细读 React | React Router 路由切换原理

2022 北京冬奥会开幕式

此前一直在疑惑,明明 pushState()replaceState() 不触发 popstate 事件,可为什么 React Router 还能挂载对应路由的组件呢?

翻了一下 history.js 源码,终于知道原因了。

源码

假设项目路由设计如下:

import { render } from 'react-dom'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { Mine, About } from './routes'
import App from './App'const rootElement = document.getElementById('root')render(<BrowserRouter><Routes><Route path="/" exact element={<App />} /><Route path="/mine" element={<Mine />} /><Route path="/about" element={<About />} /></Routes></BrowserRouter>,rootElement
)

然后我们看下 <BrowserRouter /> 的源码(react-router-dom/modules/BrowserRouter.js),以下省略了一部分无关代码:

import React from 'react'
import { Router } from 'react-router'
import { createBrowserHistory as createHistory } from 'history'/*** The public API for a <Router> that uses HTML5 history.*/
class BrowserRouter extends React.Component {// 构建 history 对象history = createHistory(this.props)render() {// 将 history 对象等传入 <Router /> 组件return <Router history={this.history} children={this.props.children} />}
}// ...export default BrowserRouter

接着我们继续看下 <Router /> 组件的源码(react-router/modules/Router.js),如下:

import React from 'react'
import HistoryContext from './HistoryContext.js'
import RouterContext from './RouterContext.js'/*** The public API for putting history on context.*/
class Router extends React.Component {static computeRootMatch(pathname) {return { path: '/', url: '/', params: {}, isExact: pathname === '/' }}constructor(props) {super(props)this.state = {location: props.history.location}// 关键点:// 当触发 popstate 事件、// 或主动调用 props.history.push()、props.history.replace() 方法时,// 都会执行 history 对象的 listen 方法,使得执行 setState 强制更新当前组件this.unlisten = props.history.listen(location => {this.setState({ location })})}componentWillUnmount() {// 组件卸载时,解除监听if (this.unlisten) this.unlisten()}render() {return (// 由于 React Context 的特性,所有消费 RouterContext.Provider 的 Custom 组件// 在其 value 值发生变化时,都会重新渲染。// 当前 <Router /> 组件并没有做任何限制重新渲染的处理,// 因此每次 setState 都会引起 RouterContext.Provider 的 value 值发生变化。<RouterContext.Providervalue={{history: this.props.history,location: this.state.location,match: Router.computeRootMatch(this.state.location.pathname),staticContext: this.props.staticContext}}><HistoryContext.Provider children={this.props.children || null} value={this.props.history} /></RouterContext.Provider>)}
}export default Router

原因剖析

往下之前,如果对 History API 或者 URL Fragment 不了解的,可以看下这篇文章:History 对象及事件监听详解。

react-router-dom 引用了 history.js 库 ,它主要提供了三种方法:createBrowserHistorycreateHashHistorycreateMemoryHistory

它们用于构建对应模式的 history 对象(请注意,它有别于 window.history 对象),该对象的属性和方法可在 Devtools 中清晰地看到(如下图),也可查阅文档。这个太简单了,你们都懂,不说了。

本文讨论的是 History 模式,因而对应 createBrowserHistory 方法。

在构建项目路由时,选择 <BrowserRouter /> 组件,它内部是将通过 createBrowserHistory() 方法构造的 history 对象传递给 <Router /> 组件。

我们知道,在 React 应用中切换路由,它会加载对应的组件。我们知道 createBrowserHistory() 利用了 HTML5 History API 特性,但是主动调用 window.history.pushState()window.history.replaceState() 方法都不会触发 popstate 事件,因此,如果仅通过监听 popstate 事件是不能完全实现路由切换的。

那么 React Router 是如何解决问题的呢?

在前面的源码部分,其实已经添加了一些注解,<Router /> 组件它内部依赖于 Context 的 Provider/Comsumer 模式。因此,它只要做到 URL 发生变化时更新 Context.Providervalue 值即可,至于后续如何加载组件就交给 React 了(当然里面还包括 React Router 的路由匹配,但非本文讨论内容,不展开讲述)。

一般情况下,<BrowserRouter /> 都会作为整个项目的根路由,它包裹了一层 <Router /> 组件,<Router /> 组件在实例化时,设置了一个监听函数:

// props.history 就是通过 createBrowserHistory(props) 生成的对象
this.unlisten = props.history.listen(location => {// 回调函数的作用是,通过 setState 触发 Router 组件更新,// 使得 Provider 的 value 值发生变化,以带动 Consumer 的更新。this.setState({ location })
})
// this.unlisten 是一个函数,执行它内部会移除 popstate 事件监听器

Q:history.js 是如何做到每当 URL 发生变化,会触发这个回调函数的?

在 React 中是通过调用组件的 props.history.push()props.history.replace() 方法实现路由切换的。

我们来看一下 history.js 的源码(history/esm/history.js):

里面省略了一部分代码,然后分析顺序已经按顺序标注出来。

function createTransitionManager() {// ...function confirmTransitionTo(location, action, getUserConfirmation, callback) {var result = typeof prompt === 'function' ? prompt(location, action) : promptif (typeof result === 'string') {if (typeof getUserConfirmation === 'function') {getUserConfirmation(result, callback)} else {process.env.NODE_ENV !== 'production' ? warning(false, 'A history needs a getUserConfirmation function in order to use a prompt message') : void 0callback(true)}} else {// Return false from a transition hook to cancel the transition.callback(result !== false)}}var listeners = []function appendListener(fn) {var isActive = truefunction listener() {if (isActive) fn.apply(void 0, arguments)}// 添加监听器listeners.push(listener)return function () {isActive = false// 过滤重复的监听器listeners = listeners.filter(function (item) {return item !== listener})}}// 6️⃣ 执行 listeners 中所有的 listener 监听器,// 最后触发 <Router /> 中的回调函数 this.unlisten = props.history.listen(location => { this.setState({ location }) }) 逻辑function notifyListeners() {// 将类数组 arguments 转换为数组形式for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {args[_key] = arguments[_key]}listeners.forEach(function (listener) {// 回调函数将获得 location、action 两个参数return listener.apply(void 0, args)})}return {setPrompt: setPrompt,confirmTransitionTo: confirmTransitionTo,appendListener: appendListener,notifyListeners: notifyListeners}
}/*** Creates a history object that uses the HTML5 history API including* pushState, replaceState, and the popstate event.*/
function createBrowserHistory(props) {// ...// 创建 location 对象function getDOMLocation(historyState) {var _ref = historyState || {},key = _ref.key,state = _ref.statevar _window$location = window.location,pathname = _window$location.pathname,search = _window$location.search,hash = _window$location.hashvar path = pathname + search + hashif (basename) path = stripBasename(path, basename)return createLocation(path, state, key)}// ...// 创建 transitionManager 对象var transitionManager = createTransitionManager()// 5️⃣ 主要更新 history 对象,并调用 notifyListeners 方法function setState(nextState) {_extends(history, nextState)history.length = globalHistory.length// 执行 transitionManager 中的所有 listenerstransitionManager.notifyListeners(history.location, history.action)}// 3️⃣ popstate 事件监听器的处理函数function handlePopState(event) {// getDOMLocation 方法用于生成 location 对象,location: { hash, pathname, search, state }// handlePop 方法,主要是用于触发 setState 方法handlePop(getDOMLocation(event.state))}// 4️⃣ 用于调用 setState 方法function handlePop(location) {var action = 'POP'transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {if (ok) {setState({action: action,location: location})}})}// 7️⃣// 这里的 push 和 replace 方法,是利用了 window.history.pushState() 和 window.history.replaceState()// 他们不会触发 popstate 事件,因此无法执行 handlePopState 方法,因此我们需要主动执行 setState() 方法,进而// 执行 notifyListeners() 以使得 <Router /> 组件的回调被执行,使得组件进行更新。function push(path, state) {// ...var action = 'PUSH'var location = createLocation(path, state, createKey(), history.location)// 将会执行 confirmTransitionTo 的 callback 函数transitionManager.confirmTransitionTo(location, action, getUserConfirmation, function (ok) {if (!ok) returnvar href = createHref(location)var key = location.key,state = location.stateif (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() 方法,然后里面会执行 notifyListeners 方法,并触发 listeners 的所有监听器setState({action: action,location: location})}} else {window.location.href = href}})}function replace(path, state) {// 与 push 方法同理,省略...}// 8️⃣// 这里的 go()、goBack()、goForward() 全是利用了 History API 的能力,// 他们都会触发 popstate 事件,因此都会执行 handlePopState 方法。function go(n) {globalHistory.go(n)}function goBack() {go(-1)}function goForward() {go(1)}var listenerCount = 0// 2️⃣ 注册/移除 popstate 事件监听器function checkDOMListeners(delta) {listenerCount += deltaif (listenerCount === 1 && delta === 1) {// 添加 popstate 事件监听器,执行 handlePopState 时将会触发 setStatewindow.addEventListener(PopStateEvent, handlePopState)if (needsHashChangeListener) window.addEventListener(HashChangeEvent, handleHashChange)} else if (listenerCount === 0) {// 移除事件监听器window.removeEventListener(PopStateEvent, handlePopState)if (needsHashChangeListener) window.removeEventListener(HashChangeEvent, handleHashChange)}}// 1️⃣ 设置监听器,以触发 <Router /> 组件中的回调函数function listen(listener) {// 往 transitionManager 中的 listeners 数组添加新的监听器 listener,// 其中 transitionManager 对象有这些方法:{ setPrompt, confirmTransitionTo, appendListener, notifyListeners }var unlisten = transitionManager.appendListener(listener)// 负责添加、移除 popstate 事件监听器checkDOMListeners(1)// 执行回调函数移除 listener 监听器return function () {checkDOMListeners(-1)unlisten()}}var history = {length: globalHistory.length,action: 'POP',location: initialLocation,createHref: createHref,push: push,replace: replace,go: go,goBack: goBack,goForward: goForward,block: block,listen: listen}return history
}

以下是 history.js 中创建的 historylocation 对象的一些属性和方法:

先回到 <Router /> 组件中的 history.listen(fn),它主要做几件事:

  • fn 保存在负责存储监听器的 listeners 数组中,未来它将会被 notifyListeners() 方法调用。
  • 注册 popstate 事件监听器,触发之后,会执行 notifyListeners() 方法
  • 在 React 组件中调用 props.history.push() 等方法,也将会触发 notifyListeners() 方法。
  • 执行 notifyListeners() 方法,会执行 listeners 中所有的 listener,因此 fn 将会被触发。
  • 执行 fn() 触发 Component 中的 setState() 方法更新 <Router /> 组件,即 Router.Providervalue 发生改变,那么 Router.Consumer 就会跟着更新

所以,React Router 是利用了 Context 的 Provider/Custom 特性,解决了 pushState/replaceState 不触发 popstate 事件时实现了路由切换的问题。

The end.



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

相关文章:

细读 React | React Router 路由切换原理

2022 北京冬奥会开幕式 此前一直在疑惑&#xff0c;明明 pushState()、replaceState() 不触发 popstate 事件&#xff0c;可为什么 React Router 还能挂载对应路由的组件呢&#xff1f; 翻了一下 history.js 源码&#xff0c;终于知道原因了。 源码 假设项目路由设计如下&#…...

kubernetes学习-Helm 包管理器(十二)

一、Helm解释 Helm&#xff1a;Kubernetes 的软件包管理器 Helm 被誉为查找、分享及使用 Kubernetes 软件组件的最佳途径。作为 Kubernetes 包的管理工具&#xff0c;Helm 专注于管理名为 chart 的软件包。以下是 Helm 所具备的核心功能&#xff1a; 创建新 chart&#xff1…...

PbootCMS最新代码注入漏洞(CNVD-2025-01710、CVE-2024-12789)

PbootCMS是一套高效、简洁、 强悍的可免费商用的CMS源码&#xff0c;使用PHPMySQL开发&#xff0c;能够满足各类企业网站开发建设的需要。 国家信息安全漏洞共享平台于2025-01-14公布该程序存在代码注入漏洞。 漏洞编号&#xff1a;CNVD-2025-01710、CVE-2024-12789 影响产品…...

网络安全与AI:数字经济发展双引擎

在2025年年初&#xff0c;一场科技攻防战引发了全球关注。国产人工智能DeepSeek的爆火&#xff0c;伴随着大规模的网络攻击事件&#xff0c;将网络安全的重要性推上了风口浪尖。 在此背景下&#xff0c;我们计划探讨网络安全与人工智能如何为数字经济发展提供强大动力。网络安…...

【DeepSeek × Postman】请求回复

新建一个集合 在 Postman 中创建一个测试集合 DeepSeek API Test&#xff0c;并创建一个关联的测试环境 DeepSeek API Env&#xff0c;同时定义两个变量 base_url 和 api_key 的步骤如下&#xff1a; 1. 创建测试集合 DeepSeek API Test 打开 Postman。点击左侧导航栏中的 Co…...

如何将网站提交百度收录完整SEO教程

百度收录是中文网站获取流量的重要渠道。本文以我的网站&#xff0c;www.mnxz.fun&#xff08;当然现在没啥流量&#xff09; 为例&#xff0c;详细讲解从提交收录到自动化维护的全流程。 一、百度收录提交方法 1. 验证网站所有权 1、登录百度搜索资源平台 2、选择「用户中心…...

【unity实战】实现摄像机跟随效果

考虑到每个人基础可能不一样,且并不是所有人都有同时做2D、3D开发的需求,所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要讲解C#的基础语法,包括变量、数据类型、运算符、流程控制、面向对象等,适合没有编程基础的…...

使用Hexo部署NexT主体网站

一.使用git提交文件 参考&#xff1a; 从零开始搭建个人博客&#xff08;超详细&#xff09; - 知乎 致谢&#xff01; 第一种&#xff1a;本地没有 git 仓库 直接将远程仓库 clone 到本地&#xff1b;将文件添加并 commit 到本地仓库&#xff1b;将本地仓库的内容push到远程仓…...

使用 AlexNet 实现图片分类 | PyTorch 深度学习实战

前一篇文章&#xff0c;CNN 卷积神经网络处理图片任务 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 本篇文章内容来自于 强化学习必修课&#xff1a;引领人工智能新时代【梗直哥瞿炜】 使用 AlexNet 实现图片分类…...

ES6 Proxy 用法总结以及 Object.defineProperty用法区别

Proxy 是 ES6 引入的一种强大的拦截机制&#xff0c;用于定义对象的基本操作&#xff08;如读取、赋值、删除等&#xff09;的自定义行为。相较于 Object.defineProperty&#xff0c;Proxy 提供了更灵活、全面的拦截能力。 1. Proxy 语法 const proxy new Proxy(target, hand…...

初次体验Tauri和Sycamore (2)

原创作者&#xff1a;庄晓立&#xff08;LIIGO&#xff09; 原创时间&#xff1a;2025年2月8日&#xff08;首次发布时间&#xff09; 原创链接&#xff1a;https://blog.csdn.net/liigo/article/details/145520637 版权所有&#xff0c;转载请注明出处。 关键词&#xff1a;Sy…...

Qt - 地图相关 —— 2、Qt调用百度在线地图功能示例全集,包含线路规划、地铁线路查询等(附源码)

效果:由于录制软件导致exe显示不正常,实际运行没有任何问题。 作者其他相关文章链接:           Qt - 地图相关 —— 1、加载百度在线地图(附源码)...

ffmpeg基本用法

一、用法 ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}... 说明&#xff1a; global options&#xff1a;全局选项&#xff0c;应用于整个 FFmpeg 进程&#xff0c;它们通常不受输入或输出部分的限制。 infile options&#xff1a;输入选…...

redis底层数据结构——链表

文章目录 定义内部实现总结 定义 链表提供了高效的节点重排能力&#xff0c;以及顺序性的节点访间方式&#xff0c;并且可以通过增删节点来灵活地调整链表的长度。 作为一种常用数据结构&#xff0c;链表内置在很多高级的编程语言里面&#xff0c;因为Redis使用的C语言并没有…...

Repo命令使用

repo 命令与 git 类似&#xff0c;但它主要用于管理多个 Git 仓库的操作。以下是等效的 repo 命令&#xff1a; 1. 获取新仓库代码 克隆仓库 repo init -u <manifest_url> -b <branch_name> repo sync repo init&#xff1a;初始化 repo&#xff0c;指定远程清单…...

React 高级教程

使用 React 高级组件(HOC)实现的完整项目示例,包含权限控制、数据加载状态处理、性能优化等常见高级功能。创建一个简单的博客系统: // 项目结构: src/ |-- components/ | |-- ArticleList.jsx | |-- Article.jsx | |-- Header.jsx | |-- LoginForm.jsx | |-- U…...

Linux: ASoC 声卡硬件参数的设置过程简析

文章目录 1. 前言2. ASoC 声卡设备硬件参数2.1 将 DAI、Machine 平台的硬件参数添加到声卡2.2 打开 PCM 流时将声卡硬件参数配置到 PCM 流2.3 应用程序对 PCM 流参数进行修改调整 1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&am…...

网络基础知识与配置

目录 网络基础知识 &#xff08;一&#xff09;网络的概念 &#xff08;二&#xff09;网络协议 &#xff08;三&#xff09;网络拓扑结构 &#xff08;四&#xff09;IP地址和子网掩码 显示和配置网络接口 &#xff08;一&#xff09;在Windows系统中 &#xff08;二&a…...

【STM32】ADC|多通道ADC采集

本次实现的是ADC实现数字信号与模拟信号的转化&#xff0c;数字信号时不连续的&#xff0c;模拟信号是连续的。 1.ADC转化的原理 模拟-数字转换技术使用的是逐次逼近法&#xff0c;使用二分比较的方法来确定电压值 当单片机对应的参考电压为3.3v时&#xff0c;0~ 3.3v(模拟信…...

centos 7 关于引用stdatomic.h的问题

问题&#xff1a;/tmp/tmp4usxmdso/main.c:6:23: fatal error: stdatomic.h: No such file or directory #include <stdatomic.h> 解决步骤&#xff1a; 1.这个错误是因为缺少C编译器的标准原子操作头文件 stdatomic.h。在Linux系统中&#xff0c;我们需要安装开发工具…...

用语言模型探索语音风格空间:无需情感标签的情 感TTS

用语言模型探索语音风格空间&#xff1a;无需情感标签的情感TTS 原文&#xff1a;Exploring speech style spaces with language models: Emotional TTS without emotion labels 今天我们要说的是 一种无需情感标签的情感TTS。提出了一个基于FastSpeech2的E-TTS框架&#xff0…...

将Excel中的图片保存下载并导出

目录 效果演示 注意事项 核心代码 有需要将excel中的图片解析出来保存到本地的小伙子们看过来&#xff01;&#xff01;&#xff01; 效果演示 注意事项 仅支持xlsx格式&#xff1a;此方法适用于Office 2007及以上版本的.xlsx文件&#xff0c;旧版.xls格式无法使用。 图片名…...

2.11日学习总结

题目一 &#xff1a; AC代码 #include <stdio.h> #include <stdlib.h>// 定义长整型 typedef long long ll;// 定义求最大值和最小值的宏函数 #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))// 定义数组和变量 ll…...

安川伺服控制器MP系列优势特点及行业应用

在工业自动化领域&#xff0c;运动控制器的性能直接决定了设备的精度、效率和可靠性。作为全球领先的运动控制品牌&#xff0c;安川电机伺服控制器凭借其卓越的技术优势和广泛的应用场景&#xff0c;正在为智能制造注入强劲动力&#xff01; MP3100&#xff1a;主板型运动控制…...

【腾讯地图】录入经纬度功能 - 支持地图选点

目录 效果展示代码引入地图服务地址弹框中输入框 - 支持手动输入经纬度/地图选点按钮地图选点弹框组件 当前文章 - 地图功能与 https://blog.csdn.net/m0_53562074/article/details/143677335 功能类似 效果展示 代码 引入地图服务地址 public/index.html <!-- 互联网地图…...

Mybatis快速入门与核心知识总结

Mybatis 1. 实体类&#xff08;Entity Class&#xff09;1.1 实体类的定义1.2 简化编写1.2.1 Data1.2.2 AllArgsConstructor1.2.3 NoArgsConstructor 2. 创建 Mapper 接口2.1 Param2.2 #{} 占位符2.3 SQL 预编译 3. 配置 MyBatis XML 映射文件&#xff08;可选&#xff09;3.1 …...

RK3568平台开发系列讲解(调试篇)网卡队列均衡负载

🚀返回专栏总目录 文章目录 一、RPS 的介绍1. RPS 的工作原理2. RPS 配置3. 启用和调优 RPS4. RPS 优势二、下行测试iperf测试沉淀、分享、成长,让自己和他人都能有所收获!😄 RPS(Receive Packet Steering) 是一种用于提高网络接收性能的技术,通常用于多核处理器系统中…...

Matlab机械手碰撞检测应用

本文包含三个部分&#xff1a; Matlab碰撞检测的实现URDF文件的制作机械手STL文件添加夹爪 一.Matlab碰撞检测的实现 首先上代码 %% 检测在结构环境中机器人是否与物体之间发生碰撞情况&#xff0c;如何避免&#xff1f; % https://www.mathworks.com/help/robotics/ug/che…...

【前端】几种常见的跨域解决方案代理的概念

几种常见的跨域解决方案&代理的概念 一、常见的跨域解决方案1. 服务端配置CORS&#xff08;Cross-Origin Resource Sharing&#xff09;&#xff1a;2. Nginx代理3. Vue CLI配置代理&#xff1a;4 .uni-app在manifest.json中配置代理来解决&#xff1a;5. 使用WebSocket通讯…...

服务器有多少线程?发起一个请求调用第三方服务,是新增加一个请求吗?如果服务器线程使用完了怎么办?

目录 1. 服务器有多少线程? (1)服务器类型 (2)配置参数 (3)硬件资源 2. 发起一个请求调用第三方服务,是新增加一个线程吗? (1)同步调用 (2)异步调用 (3)HTTP 客户端 3. 如果服务器线程使用完了怎么办? (1)请求被拒绝 (2)性能下降 (3)解决方案…...

【Spring AI】基于SpringAI+Vue3+ElementPlus的QA系统实现一

整理不易&#xff0c;请不要吝啬你的赞和收藏。 1. 前言 这是 SpringAI 系列的第二篇文章&#xff0c;这篇文章将介绍如何基于 RAG 技术&#xff0c;使用 SpringAI Vue3 ElementPlus 实现一个 Q&A 系统。本文使用 deepseek 的 DeepSeek-V3 作为聊天模型&#xff0c;使用…...

前端快速生成接口方法

大家好&#xff0c;我是苏麟&#xff0c;今天聊一下OpenApi。 官网 &#xff1a; umijs/openapi - npm 安装命令 npm i --save-dev umijs/openapi 在根目录&#xff08;项目目录下&#xff09;创建文件 openapi.config.js import { generateService } from umijs/openapi// 自…...

【Qt 常用控件】多元素控件(QListWidget、QTabelWidgt、QTreeWidget)

**View和**Widget的区别&#xff1f; **View的实现更底层&#xff0c;**Widget是基于**View封装实现的更易用的类型。 **View使用MVC结构 MVC是软件开发中 经典的 软件结构 组织形式&#xff0c;软件设计模式。 M&#xff08;model&#xff09;模型。管理应用程序的核心数据和…...

java 读取sq3所有表数据到objectNode

1.实现效果&#xff1a;将sq3中所有表的所有字段读到objectNode 对象中&#xff0c;兼容后期表字段增删情况&#xff0c;数据组织形式如下图所示&#xff1a; 代码截图&#xff1a; 代码如下&#xff1a; package com.xxx.check.util;import java.sql.*; import java.util.Arr…...

react redux用法学习

参考资料&#xff1a; https://www.bilibili.com/video/BV1ZB4y1Z7o8 https://cn.redux.js.org/tutorials/essentials/part-5-async-logic AI工具&#xff1a;deepseek&#xff0c;通义灵码 第一天 安装相关依赖&#xff1a; 使用redux的中间件&#xff1a; npm i react-redu…...

C++20中的std::atomic_ref

一、std::atomic_ref 我们在学习C11后的原子操作时&#xff0c;都需要提前定义好std::atomic变量&#xff0c;然后才可以在后续的应用程序中进行使用。原子操作的优势在很多场合下优势非常明显&#xff0c;所以这也使得很多开发者越来习惯使用原子变量。 但是&#xff0c;在实…...

encodeURI(),encodeURIComponent()区别

encodeURI()&#xff0c;encodeURIComponent()区别 encodeURI(): 对整个url(链接/网络链接)进行编码。 对中文&#xff0c;完全编码。 对英文不带空格则不会编码&#xff0c;带空格则会对空格编码。 解码&#xff1a;decodeURI() 例如&#xff1a; let ChineseUrl "htt…...

Selenium:网页frame与多窗口处理

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、多窗口处理 1.1、多窗口简介 点击某些链接&#xff0c;会重新打开⼀个窗⼜&#xff0c;对于这种情况&#xff0c;想在新页⾯上操作&#xff0c;就 得先切换窗…...

自动驾驶---如何打造一款属于自己的自动驾驶系统

在笔者的专栏《自动驾驶Planning决策规划》中&#xff0c;主要讲解了行车的相关知识&#xff0c;从Routing&#xff0c;到Behavior Planning&#xff0c;再到Motion Planning&#xff0c;以及最后的Control&#xff0c;笔者都做了相关介绍&#xff0c;其中主要包括算法在量产上…...

开源机器人+具身智能 解决方案+AI

开源机器人、具身智能(Embodied Intelligence)以及AI技术的结合,可以为机器人领域带来全新的解决方案。以下是这一结合的可能方向和具体方案: 1. 开源机器人平台 开源机器人平台为开发者提供了灵活的基础架构,可以在此基础上结合具身智能和AI技术。以下是一些常用的开源机…...

【web自动化】指定chromedriver以及chrome路径

selenium自动化&#xff0c;指定chromedriver&#xff0c;以及chrome路径 对应这篇文章&#xff0c;可以点击查看&#xff0c;详情 from selenium import webdriverdef get_driver():# 获取配置对象option webdriver.ChromeOptions()option.add_experimental_option("de…...

高等代数笔记—线性变换

latex花体字母与花体数字 https://blog.csdn.net/weixin_39589455/article/details/133846783 https://blog.csdn.net/orz_include/article/details/123645710线性变换 线性空间 V V V到自身的映射称为 V V V的一个变换&#xff0c;最基本的是线性变换。 定义&#xff1a;变换…...

Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统

Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统 需求 在实际生成操作过程中&#xff0c;一般会遇到物理服务器存在多块盘的情况。 安装过程中&#xff0c;磁盘的标签是随机分配的&#xff0c;并不是空间较小的盘&#xff0c;就会使用较小的磁盘标签 而需求往往需要…...

2024BaseCTF_week4_web上

继续&#xff01;冲冲冲 目录 圣钥之战1.0 nodejs 原型 原型链 原型链污染 回到题目 flag直接读取不就行了&#xff1f; 圣钥之战1.0 from flask import Flask,request import jsonapp Flask(__name__)def merge(src, dst):for k, v in src.items():if hasattr(dst, __geti…...

大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡

大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡 背景 前端开发接口请求&#xff0c;调试&#xff0c;联调&#xff0c;接入数据&#xff0c;前端必不可少工具&#xff0c;postman是一个非常好…...

内网穿透的应用-Ubuntu本地Docker搭建pichome文件管理系统打造个人云相册

文章目录 前言1.关于pichome2.本地部署pichome3.简单使用pichome4. 安装内网穿透5.配置pichome公网地址6. 配置固定公网地址 前言 你是不是也经常遇到这样的尴尬&#xff1a;手机、电脑里堆满了照片和视频&#xff0c;想找一张特定的图片时却像在大海捞针一样无从下手&#xf…...

深度学习之神经网络框架搭建及模型优化

神经网络框架搭建及模型优化 目录 神经网络框架搭建及模型优化1 数据及配置1.1 配置1.2 数据1.3 函数导入1.4 数据函数1.5 数据打包 2 神经网络框架搭建2.1 框架确认2.2 函数搭建2.3 框架上传 3 模型优化3.1 函数理解3.2 训练模型和测试模型代码 4 最终代码测试4.1 SGD优化算法…...

DeepSeek AI R1推理大模型API集成文档

DeepSeek AI R1推理大模型API集成文档 引言 随着自然语言处理技术的飞速发展&#xff0c;大语言模型在各行各业的应用日益广泛。DeepSeek R1作为一款高性能、开源的大语言模型&#xff0c;凭借其强大的文本生成能力、高效的推理性能和灵活的接口设计&#xff0c;吸引了大量开发…...

怎麼使用靜態住宅IP進行多社媒帳號管理

隨著社交媒體平臺的多樣化&#xff0c;很多人發現一個社媒帳號已經無法滿足需求。以下是幾個常見場景&#xff1a; 企業需求&#xff1a;企業可能需要在不同平臺上運營多個品牌帳號&#xff0c;為每個市場地區單獨設立帳號。個人需求&#xff1a;一些自由職業者或內容創作者可…...

【Elasticsearch】Bucket Selector Aggregation

Elasticsearch 的Bucket Selector Aggregation是一种强大的管道聚合功能&#xff0c;用于根据条件过滤聚合结果中的桶&#xff08;buckets&#xff09;。它允许用户通过编写脚本来动态决定哪些桶应该被保留&#xff0c;哪些应该被过滤掉。以下是对Bucket Selector Aggregation的…...