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.mzph.cn/pingmian/69830.shtml

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

相关文章

使用 EDOT 监测由 OpenAI 提供支持的 Python、Node.js 和 Java 应用程序

作者&#xff1a;来自 Elastic Adrian Cole Elastic 很自豪地在我们的 Python、Node.js 和 Java EDOT SDK 中引入了 OpenAI 支持。它们为使用 OpenAI 兼容服务的应用程序添加日志、指标和跟踪&#xff0c;而无需任何代码更改。 介绍 去年&#xff0c;我们宣布了 OpenTelemetry…

RabbitMQ使用guest登录提示:User can only log in via localhost

guest用户默认是无法使用远程访问的&#xff0c;生产环境建议直接在对应服务器登录使用。 1、通过创建新增用户并赋予权限实现远程登录 添加新用户 rabbitmqctl add_user zjp zjp 设置管理员 rabbitmqctl set_user_tags zjp administrator 设置新用户的权限 rabbitmqctl…

Eclipse JSP/Servlet 深入解析

Eclipse JSP/Servlet 深入解析 引言 随着互联网的快速发展,Java Web开发技术逐渐成为企业级应用开发的主流。在Java Web开发中,JSP(JavaServer Pages)和Servlet是两个核心组件,它们共同构成了Java Web应用程序的基础。本文将深入解析Eclipse平台下的JSP/Servlet技术,帮…

【Uniapp】关于实现下拉刷新的三种方式

在小程序、h5等地方中&#xff0c;常常会用到下拉刷新这个功能&#xff0c;今天来讲解实现这个功能的三种方式&#xff1a;全局下拉刷新&#xff0c;组件局部下拉刷新&#xff0c;嵌套组件下拉刷新。 全局下拉刷新 这个方式简单&#xff0c;性能佳&#xff0c;最推荐&#xf…

Redis过期删除与内存淘汰策略面试题剖析

一、谈谈Redis过期删除策略 参考我的这篇博客“二、过期删除策略&内存淘汰策略”部分 高性能分布式缓存Redis-数据管理与性能提升之道_redis 高性能缓存数据库-CSDN博客 二、谈谈Redis内存淘汰策略 参考我的这篇博客“二、过期删除策略&内存淘汰策略”部分 高性能…

基于STM32的学习环境控制系统设计

&#x1f91e;&#x1f91e;大家好&#xff0c;这里是5132单片机毕设设计项目分享&#xff0c;今天给大家分享的是学习环境控制。 设备的详细功能见网盘中的文章《21、基于STM32的学习环境控制系统设计》&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1uWSZX2zbZwy9sY…

Linux中getifaddrs函数

文章目录 **函数原型****参数****返回值****释放资源****`struct ifaddrs` 结构****示例代码****输出示例****相关函数****总结**getifaddrs 是 Linux(以及其他 Unix-like 系统)中用于获取本机网络接口信息的系统调用。它提供了一种简单的方法来获取所有网络接口的地址信息,…

前端知识速记--JS篇:instanceof

前端知识速记–JS篇&#xff1a;instanceof 在JavaScript中&#xff0c;instanceof运算符用于检测一个对象是否是另一个对象的实例。它的基本语法为&#xff1a;obj instanceof Constructor。如果obj是Constructor的实例&#xff0c;它将返回true&#xff0c;否则返回false。这…

数智百问 | 制造企业如何降低产线检测数据的存储和管理成本?

在《“十四五”智能制造发展规划》等政策的推动下&#xff0c;以及新能源汽车、消费电子等品牌商对产品质量和供应商智能化水平要求的提升&#xff0c;半导体、电子制造、动力电池等先进制造行业企业纷纷推进产线智能化升级&#xff0c;并投入大量机器视觉检测设备以实现自动化…

数据科学之数据管理|统计学

使用python学习统计 目录 01 统计学基础 7 一、 统计学介绍 7 二、 数据和变量 8 02 描述统计 10 一、 描述统计概述 10 二、 分类变量的描述 11 三、 等距数值变量的描述 13 四、 等比数值变量的描述 16 五、 常用软件包介绍 16 六、 数值变量的描述统计 18 (一)…

Spring Boot 配置 Mybatis 读写分离

JPA 的读写分离配置不能应用在 Mybatis 上, 所以 Mybatis 要单独处理 为了不影响原有代码, 使用了增加拦截器的方式, 在拦截器里根据 SQL 的 CRUD 来路由到不同的数据源 需要单独增加Mybatis的配置 Configuration public class MyBatisConfig {Beanpublic SqlSessionFactory…

MongoDB 基本操作

一、数据库操作 1. 切换或创建数据库 使用use命令切换到指定数据库&#xff0c;若该数据库不存在&#xff0c;在首次插入数据时会自动创建。 use myDatabase 2. 查看所有数据库 使用show dbs命令查看 MongoDB 实例中的所有数据库。 show dbs 3. 删除当前数据库 使用db.…

网络安全事件分级

对网络安全事件进行必要分级&#xff0c;是做好应急响应工作的前提。网络安全事件分级要统筹考虑诸多因素&#xff0c;直观展示信息安全事件的风险程度&#xff0c;为后续处置工作提供重要参考。 一、网络安全事件的分级要素 对网络安全事件的分级主要考虑3个要素&#xff1a…

三步本地部署deepseekr1,支持macOs,ubuntu,Windows

一、ollama安装: ollama官网:Ollama Ollama 是一款支持在 Windows、macOS 和 Linux 上本地运行大型语言模型的工具。以下是针对不同操作系统的安装指南: 1、Windows 系统 下载安装包:访问 Ollama 官方下载页面,选择适用于 Windows 的安装包进行下载。 运行安装程序:下…

前端开发中处理浮点数精度丢失问题的多种方法

1. 使用 toFixed() 方法 toFixed()是 JavaScript 内置的 Number 对象方法&#xff0c;它会根据指定的小数位数返回一个字符串。这个方法在输出时对结果进行了四舍五入&#xff0c;因此它并不总是能保证数学上的精确性&#xff0c;但它对于展示目的来说通常是足够的。 let num…

MySQL中类似PostgreSQL中的string_agg函数--GROUP_CONCAT函数的使用

文章目录 结论&#xff1a;MySQL没有string_agg&#xff0c;但有GROUP_CONCATGROUP_CONCAT函数的基本用法示例注意事项 系统变量 group_concat_max_len 如何查看和设置查看当前的group_concat_max_len值设置group_concat_max_len值 相关源码相关链接 结论&#xff1a;MySQL没有…

基于Django以及vue的电子商城系统设计与实现

基于Django以及vue的电子商城系统设计与实现 引言 随着电子商务的快速发展&#xff0c;越来越多的企业和个人选择搭建线上商城&#xff0c;以提供更加便捷的购物体验。本文基于Python开发了一套电子商城系统&#xff0c;后端采用Django框架&#xff0c;前端使用Vue.js&#x…

妙用Pytest内置request Fixture 监控测试执行过程

关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理&#xff0c;构建成功的基石 在自动化测试工作之前&#xff0c;你应该知道的10条建议 在自动化测试中&#xff0c;重要的不是工具 你是否曾希望你的测试能根据命令行输入做出不同的行为&#xff1f; 也许是根据测试…

hbase快照同步到目标集群出现ERROR Multiple regions have the same startkey问题分析

问题现象 源集群表split/merge过程中创建快照,该快照同步到目标集群,目标集群恢复快照后,进行hbck检查,就会出现异常报错: ERROR Multiple regions have the same startkey; 问题分析 首先,出现上述问题可能有如下两种原因: 源集群中snapshot表本身就存在这种问题,没…

安科瑞光伏发电防逆流解决方案--守护电网安全,提升能源效率

在当今大力发展清洁能源的时代背景下&#xff0c;光伏发电作为一种可持续的能源解决方案&#xff0c; 正得到越来越广泛的应用。然而&#xff0c;光伏发电过程中出现的逆流问题&#xff0c;给电网的安全稳定 运行带来了诸多挑战。若不能有效解决&#xff0c;不仅可能影响电网…