React历代主要更新

一、React 16之前更新

React Fiber是16版本之后的一种更新机制,使用链表取代了树,是一种fiber数据结构,其有三个指针,分别指向了父节点、子节点、兄弟节点,当中断的时候会记录下当前的节点,然后继续更新,而15版本中的DOM stack不能有中断操作,它把组件渲染的工作分片,到时会主动让出渲染主线程;提炼fiber的关键词,大概给出如下几点:

fiber是一种数据结构。

fiber使用父子关系以及next的妙用,以链表形式模拟了传统调用栈。

fiber是一种调度让出机制,只在有剩余时间的情况下运行。

fiber实现了增量渲染,在浏览器允许的情况下一点点拼凑出最终渲染效果。

fiber实现了并发,为任务赋予不同优先级,保证了一有时间总是做最高优先级的事,而不是先来先占位死板的去执行。

fiber有协调与提交两个阶段,协调包含了fiber创建与diff更新,此过程可暂停。而提交必须同步执行,保证渲染不卡顿。

二、React 17更新

1、新的JSX转换,不需要手动引入react

React 16:

babel-loader会预编译JSX为 React.createElement(...)

React 17:

React 17中的 JSX 转换不会将 JSX 转换为 React.createElement,而是自动从 React 的 package 中引入react并调用。

另外此次升级不会改变 JSX 语法,旧的 JSX 转换也将继续工作。

2、事件代理更改

在React 17中,将不再在后台的文档级别附加事件处理程序,不在document对象上绑定事件,改为绑定于每个react应用的rootNode节点,因为各个应用的rootNode肯定不同,所以这样可以使多个版本的react应用同时安全的存在于页面中,不会因为事件绑定系统起冲突。react应用之间也可以安全的进行嵌套。

3、事件池(event pooling)的改变

React 17去除了事件池(event pooling),不在需要e.persist(),现在可以直接在异步事件中(回掉或timeout等)拿到事件对象,操作更加直观,不会令人迷惑。e.persist()仍然可用,但是不会有任何效果。

4、异步执行

React 17将副作用清理函数(useEffect)改为异步执行,即在浏览器渲染完毕后执行。

5、forwardRef 和 memo组件的行为

React 17中forwardRef 和 memo组件的行为会与常规函数组件和class组件保持一致。它们在返回undefined时会报错。

三、React 18更新

并发模式

v18的新特性是使用现代浏览器的特性构建的,彻底放弃对 IE 的支持。

v17 和 v18 的区别就是:从同步不可中断更新变成了异步可中断更新,v17可以通过一些试验性的API开启并发模式,而v18则全面开启并发模式。

并发模式可帮助应用保持响应,并根据用户的设备性能和网速进行适当的调整,该模式通过使渲染可中断来修复阻塞渲染限制。在 Concurrent 模式中,React 可以同时更新多个状态。

这里参考下文区分几个概念:

  • 并发模式是实现并发更新的基本前提
  • v18 中,以是否使用并发特性作为是否开启并发更新的依据。
  • 并发特性指开启并发模式后才能使用的特性,比如:useDeferredValue/useTransition

更新 render API

v18 使用 ReactDOM.createRoot() 创建一个新的根元素进行渲染,使用该 API,会自动启用并发模式。如果你升级到v18,但没有使用ReactDOM.createRoot()代替ReactDOM.render()时,控制台会打印错误日志要提醒你使用React,该警告也意味此项变更没有造成breaking change,而可以并存,当然尽量是不建议。

// v17
import ReactDOM from 'react-dom'
import App from './App'ReactDOM.render(<App />, document.getElementById('root'))// v18
import ReactDOM from 'react-dom/client'
import App from './App'ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<App />)

自动批处理

批处理是指 React 将多个状态更新,聚合到一次 render 中执行,以提升性能

在v17的批处理只会在事件处理函数中实现,而在Promise链、异步代码、原生事件处理函数中失效。而v18则所有的更新都会自动进行批处理。

// v17
const handleBatching = () => {// re-render 一次,这就是批处理的作用setCount((c) => c + 1)setFlag((f) => !f)
}// re-render两次
setTimeout(() => {setCount((c) => c + 1)setFlag((f) => !f)
}, 0)// v18
const handleBatching = () => {// re-render 一次setCount((c) => c + 1)setFlag((f) => !f)
}
// 自动批处理:re-render 一次
setTimeout(() => {setCount((c) => c + 1)setFlag((f) => !f)
}, 0)

如果在某些场景不想使用批处理,可以使用 flushSync退出批处理,强制同步执行更新。

flushSync 会以函数为作用域,函数内部的多个 setState 仍然是批量更新:

const handleAutoBatching = () => {// 退出批处理flushSync(() => {setCount((c) => c + 1)})flushSync(() => {setFlag((f) => !f)})
}

Suspense 支持 SSR

SSR 一次页面渲染的流程:

  1. 服务器获取页面所需数据
  2. 将组件渲染成 HTML 形式作为响应返回
  3. 客户端加载资源
  4. (hydrate)执行 JS,并生成页面最终内容

上述流程是串行执行的,v18前的 SSR 有一个问题就是它不允许组件"等待数据",必须收集好所有的数据,才能开始向客户端发送HTML。如果其中有一步比较慢,都会影响整体的渲染速度。

v18 中使用并发渲染特性扩展了Suspense的功能,使其支持流式 SSR,将 React 组件分解成更小的块,允许服务端一点一点返回页面,尽早发送 HTML和选择性的 hydrate, 从而可以使SSR更快的加载页面:

<Suspense fallback={<Spinner />}><Comments />
</Suspense>

startTransition

Transitions 是 React 18 引入的一个全新的并发特性。它允许你将标记更新作为一个 transitions(过渡),这会告诉 React 它们可以被中断执行,并避免回到已经可见内容的 Suspense 降级方案。本质上是用于一些不是很急迫的更新上,用来进行并发控制

在v18之前,所有的更新任务都被视为急迫的任务,而Concurrent Mode 模式能将渲染中断,可以让高优先级的任务先更新渲染。

React 的状态更新可以分为两类:

  • 紧急更新:比如点击按钮、搜索框打字是需要立即响应的行为,如果没有立即响应给用户的体验就是感觉卡顿延迟
  • 过渡/非紧急更新:将 UI 从一个视图过渡到另一个视图。一些延迟可以接受的更新操作,不需要立即响应

startTransition API 允许将更新标记为非紧急事件处理,被startTransition包裹的会延迟更新的state,期间可能被其他紧急渲染所抢占。因为 React 会在高优先级更新渲染完成之后,才会渲染低优先级任务的更新

React 无法自动识别哪些更新是优先级更高的。比如用户的键盘输入操作后,setInputValue会立即更新用户的输入到界面上,是紧急更新。而setSearchQuery是根据用户输入,查询相应的内容,是非紧急的。

const [inputValue, setInputValue] = useState()const onChange = (e)=>{setInputValue(e.target.value) // 更新用户输入值(用户打字交互的优先级应该要更高)setSearchQuery(e.target.value)  // 更新搜索列表(可能有点延迟,影响)
}return (<input value={inputValue} onChange={onChange} />
)

React无法自动识别,所以它提供了 startTransition让我们手动指定哪些更新是紧急的,哪些是非紧急的,从而让我们改善用户交互体验。

// 紧急的更新
setInputValue(e.target.value)
// 开启并发更新
startTransition(() => {setSearchQuery(input) // 非紧急的更新
})

新增 Hooks

useTransition

当有过渡任务(非紧急更新)时,我们可能需要告诉用户什么时候当前处于 pending(过渡) 状态,因此v18提供了一个带有isPending标志的 Hook useTransition来跟踪 transition 状态,用于过渡期。

useTransition 执行返回一个数组。数组有两个状态值:

  • isPending: 指处于过渡状态,正在加载中
  • startTransition: 通过回调函数将状态更新包装起来告诉 React这是一个过渡任务,是一个低优先级的更新
function TransitionTest() {const [isPending, startTransition] = useTransition()const [count, setCount] = useState(0)function handleClick() {startTransition(() => {setCount((c) => c + 1)})}return (<div>{isPending && <div>spinner...</div>}<button onClick={handleClick}>{count}</button></div>)
}

直观感觉这有点像 setTimeout,而防抖节流其实本质也是setTimeout,区别是防抖节流是控制了执行频率,让渲染次数减少了,而 v18的 transition 则没有减少渲染的次数。

useDeferredValue

useDeferredValue 和 useTransition 一样,都是标记了一次非紧急更新。useTransition是处理一段逻辑,而useDeferredValue是产生一个新状态,它是延时状态,这个新的状态则叫 DeferredValue。所以使用useDeferredValue可以推迟状态的渲染

useDeferredValue 接受一个值,并返回该值的新副本,该副本将推迟到紧急更新之后。如果当前渲染是一个紧急更新的结果,比如用户输入,React 将返回之前的值,然后在紧急渲染完成后渲染新的值。

function Typeahead() {const query = useSearchQuery('');const deferredQuery = useDeferredValue(query);// Memoizing 告诉 React 仅当 deferredQuery 改变,// 而不是 query 改变的时候才重新渲染const suggestions = useMemo(() =><SearchSuggestions query={deferredQuery} />,[deferredQuery]);return (<><SearchInput query={query} /><Suspense fallback="Loading results...">{suggestions}</Suspense></>);
}

这样一看,useDeferredValue直观就是延迟显示状态,那用防抖节流有什么区别呢?

如果使用防抖节流,比如延迟300ms显示则意味着所有用户都要延时,在渲染内容较少、用户CPU性能较好的情况下也是会延迟300ms,而且你要根据实际情况来调整延迟的合适值;但是useDeferredValue是否延迟取决于计算机的性能。

useId

useId支持同一个组件在客户端和服务端生成相同的唯一的 ID,避免 hydration 的不匹配,原理就是每个 id 代表该组件在组件树中的层级结构:

function Checkbox() {const id = useId()return (<><label htmlFor={id}>Do you like React?</label><input id={id} type="checkbox" name="react" /></>)
}
useInsertionEffect

与 useLayoutEffect 类似,但在所有 DOM 变化之前同步运行,适用于 CSS-in-JS 库

提供给第三方库的 Hook

useSyncExternalStore

useSyncExternalStore 一般是第三方状态管理库使用如 Redux。它通过强制的同步状态更新,使得外部 store 可以支持并发读取。它实现了对外部数据源订阅时不再需要 useEffect:

const state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot]);
useInsertionEffect

useInsertionEffect 仅限于 css-in-js 库使用。它允许 css-in-js 库解决在渲染中注入样式的性能问题。 执行时机在 useLayoutEffect 之前,只是此时不能使用ref和调度更新,一般用于提前注入样式:

useInsertionEffect(() => {console.log('useInsertionEffect 执行')
}, [])

四、React 19更新

Server Components 的稳定支持

Server Components 提供了一种全新的组件渲染模式,在服务器上提前渲染,减少了客户端的渲染负担。React 19 将此功能推向稳定,并引入了相关的 API 和最佳实践。

  • 支持在构建时或请求时生成组件。
  • 无需引入额外的工具链,即可与现有 React 项目集成。

原生支持 Document Metadata

React 19 原生支持 、 和 等文档元数据标签。这些标签可直接在组件中声明,React 会自动将它们提升至 ,并确保与服务端渲染和客户端渲染兼容。

这样可以直接 简化 SEO 和元数据管理逻辑,并且不需要像以前一样手动插入标签了

function BlogPost({ post }) {return (<article><h1>{post.title}</h1><title>{post.title}</title><meta name="author" content={post.author} /></article>);
}

新增 Hooks

useOptimistic

用于管理乐观更新。当执行某个操作时,可以先假设操作成功,并立即更新 UI,然后在操作完成后根据实际结果调整状态。比如点赞、评论、加入购物车等功能,我们都可以先假设成功,再根据接口返回来调整。

useActionState

用于管理与用户操作相关的状态。它能够记录和回放用户操作,帮助实现更复杂的交互和调试功能。

function ChangeName({ currentName }) {const [error, submitAction, isPending] = useActionState(async (prev, formData) => {const error = await updateName(formData.get("name"));if (error) return error;return null;});return (<form action={submitAction}><input type="text" name="name" defaultValue={currentName} /><button type="submit" disabled={isPending}>Update</button>{error && <p>{error}</p>}</form>);}

use API

React 19 引入了全新的 use API,用于在渲染期间读取资源。

例如:读取 Promise 或 Context。这种模式允许条件调用,并与 Suspense 结合使用。

  • 支持条件调用:突破了传统 Hooks 的调用限制。
  • 与 Suspense 深度集成:自动管理异步状态,简化异步渲染逻辑。
import { use } from 'react';function Comments({ commentsPromise }) {const comments = use(commentsPromise);return comments.map(comment => <p key={comment.id}>{comment}</p>);
}

ref 写法更新

import React, { forwardRef, useImperativeHandle } from 'react';// 子组件(函数组件)
const ChildComponent = forwardRef((props, ref) => {// 子组件内部的方法const handleClick = () => {console.log('Clicked in ChildComponent');};// 使用 useImperativeHandle 将方法暴露给父组件useImperativeHandle(ref, () => ({// 返回需要父组件访问的接口handleClick,}),[]);return (<button onClick={handleClick}>Click me</button>);
});
import React, { useImperativeHandle } from 'react';// 子组件(函数组件)
const ChildComponent = (({ref,...props}) => {// 子组件内部的方法const handleClick = () => {console.log('Clicked in ChildComponent');};// 使用 useImperativeHandle 将方法暴露给父组件useImperativeHandle(ref, () => ({// 返回需要父组件访问的接口handleClick,}),[]);return (<button onClick={handleClick}>Click me</button>);
});

ref 回调的清理功能

React 19 为 ref 回调增加了清理函数支持,允许在组件卸载时自动执行清理逻辑:

<input ref={(ref) => {// ref 创建时的逻辑return () => {// ref 清理时的逻辑};
}} />

支持 简写

React 19 引入了更简洁的 Context 写法,现在可以直接使用 代替 <Context.Provider>

const ThemeContext = createContext('');
function App({children}) {return <ThemeContext value="dark">{children}</ThemeContext>;
}

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

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

相关文章

【BUG】Ubuntu|有nvcc,没有nvidia-smi指令,找不到nvidia-driver安装包

很奇怪&#xff0c;本来能使用的&#xff0c;放个假回来就用不了了。 排查了以下所有步骤最终解决。 我的Ubuntu版本&#xff1a;Ubuntu22 nvcc -v&#xff1a;有。如果没有的话你需要安装“sudo apt-get install nvidia-cuda-toolkit”&#xff0c;其他问题请去别的博客查。…

spring-ai快速集成deepseek大模型

一、Spring AI简介&#xff1a;Spring AI致力于简化AI项目的开发与部署流程&#xff0c;使Java开发者能够更高效地将AI技术集成到业务系统中。它提供了开箱即用的工具和接口&#xff0c;方便集成和管理各种AI模型。 目前,Spring AI 支持的 AI 平台包括&#xff1a;OpenAI (Chat…

进阶——第十六届蓝桥杯嵌入式熟练度练习(开发板输出占空比和频率)

定义变量 uint16_t PA6_frq,PA7_frq; uint16_t PA6_duty10,PA7_duty20; 开启定时器PWM HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1); 给变量赋值 PA6_frq80000000/8000/TIM16->ARR1;PA7_frq80000000/4000/TIM17->AR…

TCNE 网络安全

一.概况 CTF&#xff08;Capture The Flag&#xff09;在网络安全领域中指的是网络技术人员之间进行技术竞技的一种比赛形式&#xff0c;它起源于1996年的DEFCON全球黑客大会&#xff0c;以代替之前黑客们通过互相发起真实攻击进行技术比拼的方式&#xff0c;现已成为全球范围网…

信呼OA办公系统sql注入漏洞分析

漏洞描述 信呼OA办公系统uploadAction存在SQL注入漏洞&#xff0c;攻击者可利用该漏洞获取数据库敏感信息。 环境搭建 源码下载地址&#xff1a;https://github.com/rainrocka/xinhu 下载后解压到本地网站根目录下&#xff0c;配置好数据库&#xff0c;然后安装即可 默认密…

springboot如何将lib和jar分离

遇到一个问题&#xff0c;就是每次maven package或者maven install后target中的jar很大&#xff0c;少的50几MB&#xff0c;大的100多兆 优化前&#xff1a; 优化后&#xff1a; 优化前 优化后压缩率77.2MB4.65MB93% 具体方案&#xff1a; pom.xml中 <build><…

ThreadLocal源码分析

文章目录 1.核心数据结构 ThreadLocalMap1.静态内部类 Entry2.真正存储数据的是table数组 2.ThreadLocal.set()方法源码详解1.set2.getMap3.ThreadLocalMap.set4.createMap5.rehash6.resize 3.ThreadLocalMap.get()详解1.get2.ThreadLocalMap.getEntry3.getEntryAfterMiss 4.Th…

VUE环境搭建

node.js安装 node npm – node Package Management 安装完成后&#xff0c;需要设置&#xff1a; npm config set prefix "D:\nodejs"注意&#xff1a;“D:\nodejs” 此处为自己安装的node.js路径。管理员身份运行 切换镜像源 npm config set registry https://r…

卷积神经网络实战人脸检测与识别

文章目录 前言一、人脸识别一般过程二、人脸检测主流算法1. MTCNN2. RetinaFace3. CenterFace4. BlazeFace5. YOLO6. SSD7. CascadeCNN 三、人脸识别主流算法1.deepface2.FaceNet3.ArcFace4.VGGFace5.DeepID 四、人脸识别系统实现0.安装教程与资源说明1. 界面采用PyQt5框架2.人…

深度学习框架探秘|Keras 应用案例解析以及 Keras vs TensorFlow vs PyTorch

引言 上一篇文章《深度学习框架探秘&#xff5c;Keras&#xff1a;深度学习的魔法钥匙》 我们初步学习了 Keras&#xff0c;包括它是什么、具备哪些优势&#xff08;简洁易用的 API、强大的兼容性、广泛的应用领域&#xff09;&#xff0c;以及基本使用方法。本文&#xff0c;…

在Win11电脑上安装mysql并成功登录

首先,参照菜鸟教程的mysql安装教程https://www.runoob.com/mysql/mysql-install.html,进行的步骤如下: 1.进入mysql官网https://dev.mysql.com/downloads/mysql/,如下图所示,选择需要的版本并下载。 2.点击 Download 按钮进入下载页面,点击下图中的 No thanks, just sta…

如何正确安装Stable Diffusion Web UI以及对应的xFormers

本文是我总结的步骤&#xff0c;验证了几次保证是对的。因为正确的安装 Stable Diffusion Web UI 以及对应的 xFormers 实在是太麻烦了&#xff0c;官方和网上的步骤都是残缺和分散的&#xff0c;加上国内网络速度不理想&#xff0c;所以需要一些额外步骤&#xff0c;之前研究出…

大模型WebUI:Gradio全解12——使用Agents和Tools智能代理工具构建UI(1)

大模型WebUI&#xff1a;Gradio全解12——使用Agents和Tools智能代理工具构建UI&#xff08;1&#xff09; 前言本篇摘要12. 使用Agents和Tools智能代理工具构建UI12.1 transformers.agents原理及示例12.1.1 代理概念、类型和构建1. 代理概念2. 代理类型3. 如何构建代理&#x…

图像变换:了解透视变换原理及OpenCV实现

图像透视变换是一种将图像从一个视角转换到另一个视角的技术&#xff0c;通常用于校正拍摄角度引起的变形&#xff0c;或者模拟不同视角下的场景。 一、图像透视变换的原理 定义 透视变换&#xff08;Perspective Transformation&#xff09;是将一个平面内的点映射到另一个平…

超纯水设备的智能化控制系统为用户带来安全简便的操作体验

随着信息技术的发展&#xff0c;智能化已经成为工业装备的重要发展方向之一。超纯水设备在这方面也走在了前列&#xff0c;配备了高性能的PLC控制系统及人机交互界面&#xff0c;实现了全方位的智能监控和自动化操作。本文将重点介绍该设备的智能化控制系统&#xff0c;探讨它如…

Cursor AI开发微信小程序教程

1. 准备工作 在开始开发之前&#xff0c;需要完成以下准备工作&#xff1a; 1.1 安装微信开发者工具 前往微信开发者工具官网下载并安装适合操作系统的开发者工具。注册微信小程序账号&#xff0c;登录微信公众平台&#xff08;https://mp.weixin.qq.com&#xff09;&#…

数仓:核心概念,数仓系统(ETL,数仓分层,数仓建模),数仓建模方法(星型模型,雪花模型,星座模型)和步骤

数仓建模的核心概念 事实表&#xff08;Fact Table&#xff09;&#xff1a; 存储业务过程的度量值&#xff08;如销售额、订单数量等&#xff09;。 通常包含外键&#xff0c;用于关联维度表。 维度表&#xff08;Dimension Table&#xff09;&#xff1a; 存储描述性信息&…

jsp页面跳转失败

今天解决一下jsp页面跳转失败的问题 在JavaWeb的学习过程中&#xff0c;编写了这样一段代码&#xff1a; <html> <body> <h2>Hello World!</h2><%--这里提交的路径&#xff0c;需要寻找到项目的路径--%> <%--${pageContext.request.context…

Linux Mem -- Where the mte store and check in the real hardware platform

目录 1 前言 2 MTE tag分类 3 Address tag 4 Memory tag 5 Tag Check 6 Cortex-A710 和 CI-700 系统示例&#xff1a; 1 前言 ARM的MTE允许分配、设置、比较一个 4bit的allocation tag 为16字节粒度的物理地址。当对MTE有一定了解后&#xff0c;应该会产生如下疑问&#…

Day1 25/2/14 FRI

【一周刷爆LeetCode&#xff0c;算法大神左神&#xff08;左程云&#xff09;耗时100天打造算法与数据结构基础到高级全家桶教程&#xff0c;直击BTAJ等一线大厂必问算法面试题真题详解&#xff08;马士兵&#xff09;】https://www.bilibili.com/video/BV13g41157hK?p3&v…