React v19.2.0更新

介绍

React 是一个用于创建用户界面的 JavaScript 库。

继 12 月的 React 19 和 6 月的 React 19.1 之后,10月1号React发布新版本v19.2。

react

变化

新功能点:

  1. Activity
  2. useEffectEvent
  3. cacheSignal
  4. Performance Tracks

新的ReactDom功能

  1. 部分预渲染

其他变化

  1. 对SSR暂停边界进行批处理
  2. SSR:对Node的Web Stream支持
  3. eslint-plugin-react-hooks V6
  4. 更新默认userId前缀

React新功能

Activity

在React19.2中,Activity支持两种模式,可见和隐藏

  • hidden:隐藏子项,卸载效果,并推迟更新,直到React没有任何东西处理
  • Visible :显示子项,挂载效果,并允许正常处理更新。

这意味着您可以预渲染并继续渲染应用程序的隐藏部分,而不会影响屏幕上可见的任何内容的性能。

您可以使用 Activity 来呈现用户可能导航到的应用程序的隐藏部分,或者保存用户导航离开的部分的状态。这有助于通过在后台加载数据、CSS 和图像来加快导航速度,并允许返回导航来维护输入字段等状态。

未来,我们计划为不同的用例向 Activity 添加更多模式。

官方案例

useEffectEvent

当前仅在 React Canary 和 实验发行版中可用

是一个 React Hook,它允许你从 Effects 中提取非反应式逻辑到一个称为 Effect Event 的可重用函数中。

参数

  • callback:包含效果事件逻辑的函数。当你使用 useEffectEvent 定义一个 Effect Event 时, 回调在调用时总是从 props 和 state 访问最新的值。这有助于避免关闭过时的问题。

返回

返回一个 Effect Event 函数。可以在 useEffectuseLayoutEffectuseInsertionEffect 中调用此函数。

注意

  • 仅在 Effects 内部调用: 效果事件只能在效果中调用。在使用它们的效果之前定义它们。不要将它们传递到其他组件或挂钩。
  • 不是依赖项快捷方式: 不要使用 useEffectEvent 来避免在 Effect 的依赖项数组中指定依赖项。这可以隐藏错误并使您的代码更难理解。如果需要,首选显式依赖项或使用 refs 来比较以前的值。
  • 用于非反应式逻辑: 仅使用 useEffectEvent 提取不依赖于更改值的逻辑。

用法

读取最新的pros和state

通常,当您访问 Effect 中的响应式值时,必须将其包含在依赖项数组中。这可以确保你的效果在该值发生变化时再次运行,这通常是所需的行为。

但在某些情况下,你可能希望读取 Effect 中的最新 props 或 state,而不会导致 Effect 在这些值发生变化时重新运行。

javascript 复制代码
import { useEffect, useContext, useEffectEvent } from 'react';

function Page({ url }) {
  const { items } = useContext(ShoppingCartContext);
  const numberOfItems = items.length;

  const onNavigate = useEffectEvent((visitedUrl) => {
    logVisit(visitedUrl, numberOfItems);
  });

  useEffect(() => {
    onNavigate(url);
  }, [url]);

  return(
  <div>3333</div>
  )
}

cacheSignal

React 服务器组件

cacheSignal 目前仅与 React 服务器组件一起使用。

cacheSignal 允许您知道 cache() 生命周期何时结束。

javascript 复制代码
import {cache, cacheSignal} from 'react';
const dedupedFetch = cache(fetch);

async function Component() {
  await dedupedFetch(url, { signal: cacheSignal() });
}

注意:

  • cacheSignal 目前仅用于 React 服务器组件。在客户端组件中,它将始终返回 null。将来,当客户端缓存刷新或失效时,它也将用于客户端组件。您不应假设它在客户端上始终为 null。
  • 如果在渲染之外调用,cacheSignal 将返回 null,以明确当前作用域不会永久缓存。

这允许你在结果不再用于缓存时清理或中止工作,例如:

  • React 已成功完成渲染
  • 渲染已中止
  • 渲染失败

文档

Performance Tracks

React 19.2 为 Chrome DevTools 性能配置文件添加了一组新的自定义轨道,以提供有关 React 应用程序性能的更多信息:

React Performance Tracks 文档解释了轨道中包含的所有内容。

Scheduler(调度器)

Scheduler 轨道显示了 React 针对不同优先级所做的工作,例如用户交互的"阻止",或 startTransition 内部更新的"过渡"。在每个轨道中,你将看到正在执行的工作类型,例如计划更新的事件,以及该更新的渲染发生时间。

我们还显示一些信息,例如何时阻止更新等待不同的优先级,或者 React 何时在继续之前等待绘制。Scheduler 轨道可帮助您了解 React 如何将代码拆分为不同的优先级,以及它完成工作的顺序。

请参阅 Scheduler 轨道文档以查看包含的所有内容。

Components(组件)

组件跟踪显示 React 正在处理的组件树,无论是为了渲染还是运行效果。在里面,你会看到诸如 "Mount" 标签,表示子组件挂载或效果挂载,或者 "Blocked" 标签,表示由于让步给 React 外部的工作而阻止渲染。

组件跟踪帮助你了解组件何时被渲染或运行效果,以及完成该工作的所需时间,以帮助识别性能问题。

参阅组件轨道文档以查看包含的所有内容。

React Dom 的新功能

部分预渲染

在 19.2 中新增了一个能力,可以在提前渲染应用的一部分,然后稍后恢复渲染。这个功能称为 "部分预渲染",允许你预先渲染应用的静态部分并从 CDN 提供,然后稍后恢复渲染外壳以填充动态内容。

要预渲染一个稍后可恢复的应用,首先调用 prerender 并传入一个 AbortController:

javascript 复制代码
const {prelude, postponed} = await prerender(<App />, {
  signal: controller.signal,
});

// Save the postponed state for later
await savePostponedState(postponed);

// Send prelude to client or CDN.

然后,您可以将 prelude shell 返回给客户端,稍后调用 resume 以"恢复"到 SSR 流:

javascript 复制代码
const postponed = await getPostponedState(request);
const resumeStream = await resume(<App />, postponed);

// Send stream to client.

或者您可以调用 resumeAndPrerender 来恢复以获取 SSG 的静态 HTML:

javascript 复制代码
const postponedState = await getPostponedState(request);
const { prelude } = await resumeAndPrerender(<App />, postponedState);

// Send complete HTML prelude to CDN.

有关详细信息,请参阅新 API 的文档:

  • react-dom/server

    • resume:用于 Web Streams。
    • resumeToPipeableStream 的节点流。
  • react-dom/static

    • resumeAndPrerender 用于 Web 流。
    • resumeAndPrerenderToNodeStream 用于节点流。

此外,预呈现 API 现在返回延迟状态以传递给恢复 API。

显著变化

SSR 中的 Suspense 边界批处理

修复了一个行为性错误,该错误导致 Suspense 边界会根据是在客户端渲染还是从服务器端渲染流式传输而显示不同的内容。从 19.2 开始,React 将在短时间内批量显示服务器渲染的 Suspense 边界,以允许更多内容一起显示并与客户端渲染的行为保持一致。

以前,在流式传输服务器端渲染期间,Suspense 内容会立即替换后备内容。

在 React 19.2 中,Suspense 边界会在短时间内进行批处理,以允许一起揭示更多内容。

此修复还为支持 SSR 中的 <ViewTransition> 准备了应用程序。通过一起揭示更多内容,动画可以在更大的内容批次中运行,并避免链式动画内容流接近在一起。

注意:React 使用启发式方法来确保节流不会影响核心网页指标和搜索排名。例如,如果页面总加载时间接近 2.5 秒(这是被认为是 LCP 的 "良好" 时间),React 将停止批处理并立即揭示内容,以确保节流不会成为错过指标的原因。

SSR:对 Node 的 Web Streams 支持

React 19.2 增加了对 Web Streams 的支持,用于在 Node.js 中流式传输 SSR:

  • renderToReadableStream现在可用于 Node.js
  • prerender现在可用于 Node.js

以及新的 resumeAPI:

  • resume适用于 Node.js。

  • resumeAndPrerender适用于 Node.js。

    在 Node.js 中优先使用 Node Streams 进行服务器端渲染
    在 Node.js 环境中,官方仍然强烈建议使用 Node Streams API:
    renderToPipeableStream
    resumeToPipeableStream
    prerenderToNodeStream
    resumeAndPrerenderToNodeStream
    这是因为 Node Streams 比 Node 中的 Web Streams 快得多,并且 Web Streams 默认不支持压缩,导致用户意外错过了流式传输的好处

eslint-plugin-react-hooks v6

还发布了 eslint-plugin-react-hooks@6.1.1,默认情况下在 recommended 预设中使用扁平配置,并为新的 React 编译器驱动规则启用选择加入。

要继续使用旧配置,可以更改为 recommended-legacy

less 复制代码
- extends: ['plugin:react-hooks/recommended']
+ extends: ['plugin:react-hooks/recommended-legacy']

有关启用编译器规则的完整列表,请查看 linter 文档

查看 eslint-plugin-react-hooks 变更日志以获取完整的更改列表

更新默认 useId 前缀

在 19.2 中,我们将默认的 useId 前缀从 :r: (19.0.0) 或 <<r>> (19.1.0) 更新为 r

使用对 CSS 选择器无效的特殊字符的初衷是它不太可能与用户编写的 ID 发生冲突。但是,为了支持 View Transitions,我们需要确保 useId 生成的 ID 对 view-transition-name 和 XML 1.0 名称有效。

其他显著变化

  • react-dom:允许在可提升样式上使用 nonce #32461
  • react-dom:如果 React 拥有的节点也有文本内容,则警告使用 React 拥有的节点作为容器 #32774

值得注意的错误修复

  • react:将上下文字符串化为"SomeContext"而不是"SomeContext.Provider" #33507
  • react:修复 popstate 事件中的无限 useDeferredValue 循环 #32821
  • react:修复将初始值传递给 useDeferredValue 时的错误 #34376
  • react:修复使用客户端作提交表单时崩溃的问题 #33055
  • react:如果脱水悬念边界重新悬浮,则隐藏/取消隐藏它们的内容 #32900
  • react: 避免在热重载期间在宽树上出现堆栈溢出 #34145
  • react:改进各个地方的组件堆栈 #33629#33724#32735#33723
  • react:修复 React.lazy-ed 组件中 React.use 的错误 #33941
  • react-dom:使用 ARIA 1.3 属性时停止警告 #34264
  • react-dom:修复 Suspense 后备中深度嵌套 Suspense 的错误 #33467
  • react-dom:渲染时中止后避免挂起 #34192

有关更改的完整列表,请参阅更新日志

demo

js 复制代码
import { useState,Activity,useEffectEvent,useEffect } from 'react';


export default function App() {
  const [isShow, setIsShow] = useState(true);
  const [theme, setTheme] = useState('light');
  const [count, setCount] = useState(0);

  const onLog = useEffectEvent(() => {
    console.log(333,theme)
  })

  useEffect(() => {
    onLog()
  }, [count])
  

  return (
    <>
      <h3>Activity</h3>
      <Activity mode={isShow ? 'visible' : 'hidden'}>
        eeeee
      </Activity>
        <button onClick={() => setIsShow(!isShow)}>
          点我
        </button>
      <h3>useEffectEvent</h3>
      <button onClick={() => setCount(count + 1)}>
        点我2
      </button>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        点我3
      </button>
    </>
  );
}

```js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./styles.css";

import App from "./App";

const root = createRoot(document.getElementById("root"));
root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
``

```js
{
  "name": "react.dev",
  "version": "0.0.0",
  "main": "/src/index.js",
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "dependencies": {
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-scripts": "^5.0.0"
  },
  "devDependencies": {},
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
相关推荐
电蚊拍3 小时前
ADB 实现手机访问电脑上运行的网站,真机调试H5网站
前端
浩男孩3 小时前
🍀上班摸鱼,手搓了个分页器组件
前端
朕的剑还未配妥3 小时前
vue2项目中使用markdown-it插件教程,同时解决代码块和较长单词不换行问题
前端
清羽_ls3 小时前
前端代码CR小知识点汇总
前端·cr
WestWong3 小时前
基于 Web 技术栈的跨端开发模版
前端
饮水机战神3 小时前
小程序被下架后,我连夜加了个 "安全接口"
前端·javascript
小old弟3 小时前
小程序开发:原生 vs 跨平台框架全解析
前端
閞杺哋笨小孩3 小时前
Vue3 点击指令(防抖 / 节流)
前端·vue.js
加油吧zkf3 小时前
Python入门:从零开始的完整学习指南
开发语言·前端·python