React正式更新!开始学习React 19!

news2024/11/25 2:43:45

本文为原创文章,原文链接:J实验室,未经授权请勿转载

今年2月份,React 发布消息确认今年发布 v19 版本,尘封两年的版本号终于要更新了(详情点击:React 19 发布在即,抢先学习一下新特性)。那时候,React 成员 Andrew Clark 明确了新版本将在3月或4月发布。

要不怎么说「DDL是第一生产力」,这不4月底了,新版本就踩点发布了。这次发布的版本号是19.0.0-Beta。

虽然只是 Beta 版,但也够让社区兴奋了:

Dan 说「they did what」

Andrew Clark 说「React 19: Never forwardRef again」

Josh W. Comeau 说「Lots of nice quality-of-life improvements here!」

唯一的遗憾是,经 React 成员 lauren 确认,React Compiler 又跳票了。这个东西原来的名称叫做「React Forget」,真就是 Forget 属性拉满了。

总结一下 19.0.0-Beta 版本的发布的特性就是:

  1. 一个 Actions
  2. 三个新 hook
  3. 一个新 API
  4. ref 和 context 用法更方便
  5. 其他支撑类更新、服务端能力更新

接下来本文一个个介绍。

💡欢迎加入「🌍独立全栈开发交流群」,一起学习交流前端和Node技术

Action

Actions 不是一个 API,是一种简化请求数据处理的方法统称。一个合格的 Actions 要能够简化异步操作,让开发者更专注于业务逻辑而不是状态管理。

让我们通过一个简单的例子来理解Actions的作用。假设我们有一个表单,用户可以通过该表单更新他们的姓名。以前,我们可能会使用useState来手动管理表单状态、错误状态和提交状态,代码可能会看起来像这样:

function UpdateName() {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, setIsPending] = useState(false);

  const handleSubmit = async () => {
    setIsPending(true);
    const error = await updateName(name);
    setIsPending(false);
    if (error) {
      setError(error);
      return;
    } 
    redirect("/path");
  };

  return (
    <div>
      <input value={name} onChange={(event) => setName(event.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </div>
  );
}

这段代码需要手动处理许多细节。但是,有了 React 19 的 Actions,情况就有所优化,我们可以使用 useTransition hook 来处理表单提交,它会自动处理 pending 状态,让我们的代码更加简洁:

function UpdateName() {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, startTransition] = useTransition();

  const handleSubmit = async () => {
    startTransition(async () => {
      const error = await updateName(name);
      if (error) {
        setError(error);
        return;
      } 
      redirect("/path");
    })
  };

  return (
    <div>
      <input value={name} onChange={(event) => setName(event.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </div>
  );
}

handleSubmit 函数中,异步请求的逻辑被放入 startTransition 的回调中。startTransition 被调用时,React 会立即将 isPending 设为 true,表示过渡(请求)正在进行。然后 React 会在后台执行 startTransition 的回调函数,发送异步请求。在请求完成后,React 会自动将 isPending 切换为 false。

我们只要将 isPending 绑定到提交按钮的 disabled 属性,这样在请求进行期间按钮会自动进入禁用状态,避免用户重复提交。

下面总结一下 React 对 Actions 的约定和说明:

  • 命名约定:使用异步过渡的函数可以被称为“Actions”。
  • 挂起状态:Actions 自动管理提交数据的挂起状态。当发起请求时,挂起状态会自动启动,当最终状态更新后,挂起状态就会自动重置。这样可以确保用户在等待数据提交时能够获得反馈,同时在请求完成后清除挂起状态。
  • 乐观更新:Actions 支持乐观更新,即在等待请求提交时就向用户显示正确的提交结果。如果最终请求失败,乐观更新会自动恢复到其原始值。
  • 错误处理:Actions 提供了内置的错误处理功能。当请求失败时,你可以使用错误边界来显示错误信息。
  • 表单支持<form> 元素现在支持将函数传递给 actionformAction 属性。通过将函数传递给 action 属性,可以使用 Actions 来处理表单提交,默认情况下会在提交后自动重置表单。这简化了表单处理的过程,使其更加直观和高效。

三个新 Hook

为什么要先介绍 Actions 呢?因为 React 19 在 Actions 基础上引入了三个新 Hook,每一个都是为了简化开发者操作状态的复杂度。

useOptimistic

useOptimistic 的主要目的是让我们可以在等待异步操作结果的时候,先假设操作成功并更新状态,然后再根据实际结果来确认状态。

它的基本用法如下:

import { useOptimistic } from 'react';

function AppContainer() {
  const [optimisticState, addOptimistic] = useOptimistic(
    state,
    // updateFn
    (currentState, optimisticValue) => {
      // merge and return new state
      // with optimistic value
    }
  );
}

其中:

  • state: 初始状态和没有正在进行的操作时返回的状态。
  • updateFn(currentState, optimisticValue): 一个纯函数,接受当前状态和 addOptimistic 传入的乐观更新值,返回合并后的乐观状态。
  • optimisticState: 乐观状态,如果没有正在进行的操作,则等于 state,否则等于 updateFn 的返回值。
  • addOptimistic: 一个用于触发乐观更新的函数,接受一个任意类型的 optimisticValue 参数,并将其传递给 updateFn

useOptimistic 的使用场景非常广泛,例如:表单提交、点赞、收藏、删除等需要即时反馈的场景均适用。

这是一个删除数据乐观更新的例子:

import React, { useState } from 'react';
import { useOptimistic } from 'react';

function AppContainer() {
	// 默认数据
  const [state, setState] = useState([
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
    { id: 3, name: 'Item 3' },
  ]);

	// 定义更新函数,该函数基于当前状态和乐观值(要删除的条目的ID)来更新状态
  const updateFn = (currentState, optimisticId) => {
    return currentState.filter(item => item.id !== optimisticId);
  };

  const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);

	// 删除item
  const deleteItem = async (itemId) => {
    // 首先乐观地更新 UI
    addOptimistic(itemId);

    // 模拟 API 请求延迟
    setTimeout(() => {
      // 假设这里是 API 删除调用,完成后更新实际状态
      setItems(currentItems => currentItems.filter(item => item.id !== itemId));
    }, 2000);
  };

  return (
    <div>
      <h1>Optimistically Deleting Items</h1>
      <ul>
        {optimisticState.map(item => (
          <li key={item.id}>
            {item.name} <button onClick={() => deleteItem(item.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default AppContainer;

useActionState

useActionState 原名叫做 useFormState,19版本启用新名称,返回参数也发生了变化(奇怪的是,React 还未更新 useActionState 的文档,欺负程序员不看文档吗?🐶)。
在这里插入图片描述

这是 useActionState 的最新基本用法:

const [state, action, pending] = useActionState(fn, initialState, permalink?);

其中返回参数有:

  • state: 表示当前的状态。在第一次渲染时,它等于初始状态 initialState。在执行操作后,它将是最新结果。
  • action: 这是一个函数,用于执行操作。当调用这个函数时,它将触发 fn 函数的执行,并更新状态。
  • pending: 这是新增参数,它是一个布尔值,表示当前是否正在执行操作。如果正在执行操作,则为 true,否则为 false

传入的参数有:

  • fn:这是一个函数,action被调用时会触发,随后返回新的值。
  • initialState:这是初始值,如果没有初值,要设置为null。
  • permalink:这是一个可选的字符串参数,通常与server action一起使用。

下面是 useActionState 与 form action 一起使用的例子,实现了更新名称的功能,如果更新失败,页面上显示 error,如果更新成功,跳转到更新后的页面:

import { useActionState } from 'react';

function ChangeName({ name, setName }) {
  // 使用 useActionState 创建与表单操作相关联的状态
  const [error, submitAction, isPending] = useActionState(
    // 第一个参数:表单操作函数
    async (previousState, formData) => {
      // 在此定义表单操作的逻辑
      // 这个函数会在表单提交时被调用
      // 它接收两个参数:
      // - previousState: 前一个状态,初始为 null,之后为上一次操作的返回值
      // - formData: 表单数据对象,可通过 formData.get("name") 获取表单字段的值
      const error = await updateName(formData.get("name"));

      // 如果操作中出现了错误,则返回错误信息
      if (error) {
        return error;
      }

      // 如果操作成功,则执行重定向
      redirect("/path");
    }, 
    // 第二个参数:初始状态,这里为 null,因为初始状态并不重要
    null
  );

  // 返回表单及相关的状态和行为
  return (
    <form action={submitAction}>
      <input type="text" name="name" />
      <button type="submit" disabled={isPending}>
        提交
      </button>
      
      {/* 错误信息 */}
      {error && <p>{error}</p>}
    </form>
  );
}

useFormStatus

useFormStatus 用来获取表单提交的状态信息。它的基本用法如下:

const { pending, data, method, action } = useFormStatus();

其中:

  • pending: 一个布尔值,表示父级 <form> 是否正在提交。如果为 true,表示表单正在提交,否则为 false
  • data: 一个实现了 FormData 接口的对象,包含父级 <form> 正在提交的数据。如果没有正在进行的提交或没有父级 <form>,则为 null
  • method: 一个字符串值,表示父级 <form> 使用的 HTTP 方法,可以是 get 或 post。
  • action: 一个指向传递给父级 <form> 的 action 属性的函数的引用。如果没有父级 <form>,则该属性为 null

例如,在 form action 中,开发者可以通过 useFormStatus 获取表单状态:

import { useFormStatus } from "react-dom";
import action from './actions';

function Submit() {
  const status = useFormStatus();
  return <button disabled={status.pending}>Submit</button>
}

export default function App() {
  return (
    <form action={action}>
      <Submit />
    </form>
  );
}

这个写法是不是熟悉又陌生?如果你想到了 context,那就对了,你可以理解为 useFormStatus 替代了一部分 context provider 的能力,而且写法比 context 要更加简洁。

使用 useFormStatus 还有两个注意点:

  1. useFormStatus Hook 必须在渲染在 <form> 内部的组件中调用。
  2. useFormStatus 只会返回父级 <form> 的状态信息,而不会返回同一组件或其子组件中任何其他 <form> 的状态信息。

一个新 API——use

以前 use 是被归类到 hook,但是 19 版本的文档把 use 放在 API 文档里面,所以它就成了一个新的 API 啦!

use 用于在组件中读取资源的值,这个资源可以是一个 Promise 或者一个 context。

它的基本用法如下:

const value = use(resource);

在实际代码中可能是这样:

import { use } from 'react';

function MessageComponent({ messagePromise }) {
  const message = use(messagePromise);
  const theme = use(ThemeContext);
  // ...

use 主要是给 Next.js 这样的上层框架使用的。以 Next.js 为例,如果是在服务端组件中获取数据,更推荐使用 async…await,而不是 use。如果是在客户端组件中获取数据,也推荐在服务端组件里创建 Promise,以 props 传递给客户端组件调用。

use 还可以与 Suspense 边界共用。如果调用 use 的组件被包裹在一个 Suspense 边界内,会显示指定的 fallback。一旦 Promise 被 resolve,Suspense 的 fallback 就会被返回的数据替换。如果传给 use 的 Promise 被 reject,最近的错误边界的 fallback 将会被显示。

ref 和 context 用法简化

如果你只使用 React 客户端的能力,那么这一节介绍的变更会是你最关注的。

ref 抛弃 forwardRef

你还记得被 forwardRef 支配的恐惧吗?从 React 19 开始,我们可以抛弃 forwardRef 了。现在开始,ref 可以当作 prop 进行传递。

举个例子:假设我们有一个函数组件 TextInput,它是一个简单的输入框组件,接受一个 placeholder 属性用于设置输入框的占位符文本。现在,我们希望在父组件中获取到输入框的引用,以便在需要时聚焦到输入框上,代码可以这么写:

import React, { useRef } from 'react';

// 定义一个函数组件 TextInput
function TextInput({ placeholder, ref }) {
  return <input placeholder={placeholder} ref={ref} />;
}

// 父组件
function ParentComponent() {
  // 创建一个 ref 来存储输入框的引用
  const inputRef = useRef(null);

  // 在某个事件处理函数中获取输入框的引用并聚焦
  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      {/* 
        将 inputRef 传递给 TextInput 组件,
        这样 TextInput 组件内部就可以使用这个 ref 了
      */}
      <TextInput placeholder="Enter your name" ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

export default ParentComponent;

是不是心智负担比使用 forwardRef 要轻得多?

context 可当作 provider

从在 React 19 开始,开发者可以直接将 <Context> 直接作为 provider,而不是使用 <Context.Provider>

假设我们有一个名为 ThemeContext 的 context,用于管理主题信息。在 React 19 中,我们可以像下面这样使用 <ThemeContext> 作为提供者:

import React, { createContext } from 'react';

// 创建一个主题上下文
const ThemeContext = createContext('');

// App 组件作为主题提供者
function App({ children }) {
  return (
    <ThemeContext value="dark">
      {children}
    </ThemeContext>
  );
}

未来 ThemeContext.Provider 会被弃用并移除。

其他更新

本次发布的新特性还有一些属于支撑类特性和拓展服务端能力的特性,因为纯客户端的 React 开发中使用场景很少,所以不再详细介绍,只简单提炼要点:

  • 服务端组件和 server actions 将成为稳定特性,这两个概念属于熟悉 Next.js/Remix 的人已经烂熟于心,而不用 Next.js/Remix 的人根本用不到。

  • useDeferredValue 增加了第二个参数,可选,用来表示初始值。即现在 useDeferredValue 的用法是这样: const value = useDeferredValue(deferredValue, initialValue?);

  • 支持在 React 代码里编写 document metadata,即在页面组件编写<title> <link><meta> 标签会自动添加应用的 <head> 上面:

    function BlogPost({post}) {
      return (
        <article>
          <h1>{post.title}</h1>
          <title>{post.title}</title>
          <meta name="author" content="Josh" />
          <link rel="author" href="https://twitter.com/joshcstory/" />
          <meta name="keywords" content={post.keywords} />
          <p>
            Eee equals em-see-squared...
          </p>
        </article>
      );
    }
    
  • 支持在 React 代码里编写 stylesheets,即在页面组件编写 <link rel="stylesheet" href="...">

  • 支持在 React 代码里编写 <script async="" src="...">,最终也会自动添加到 <head> 标签内

  • 支持预加载资源,最终也会自动添加到 <head> 标签内:

    import { prefetchDNS, preconnect, preload, preinit } from 'react-dom'
    function MyComponent() {
      preinit('https://.../path/to/some/script.js', {as: 'script' }) // loads and executes this script eagerly
      preload('https://.../path/to/font.woff', { as: 'font' }) // preloads this font
      preload('https://.../path/to/stylesheet.css', { as: 'style' }) // preloads this stylesheet
      prefetchDNS('https://...') // when you may not actually request anything from this host
      preconnect('https://...') // when you will request something but aren't sure what
    }
    

总结

最后,让我用黄玄的一段话作为总结:「Probably the single most critical principle I’ve learned from React is to be fearless in defining new conceptual abstractions and never compromise on the accuracy and composability of these definitions——我从 React 身上学到的最重要的一条原则可能就是,在定义新的概念抽象时要无所畏惧,绝不要在这些定义的准确性和可组合性上妥协」。

关于我

全栈工程师,Next.js 开源手艺人,AI降临派。

今年致力于 Next.js 和 Node.js 领域的开源项目开发和知识分享。

欢迎来交个朋友~

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

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

相关文章

FSNotes for Mac v6.7.1中文激活版:强大的笔记管理工具

FSNotes for Mac是一款功能强大的文本处理与笔记管理工具&#xff0c;为Mac用户提供了一个直观、高效的笔记记录和整理平台。 FSNotes for Mac v6.7.1中文激活版下载 FSNotes支持Markdown语法&#xff0c;使用户能够轻松设置笔记格式并添加链接、图像等元素&#xff0c;实现笔记…

Linux下启动jenkins报错问题解决

jenkins端口报错 java.io.IOException: Failed to start Jettyat winstone.Launcher.<init>(Launcher.java:209)at winstone.Launcher.main(Launcher.java:496)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.int…

【氮化镓】AlGaN/GaN HEMTs沟道温度测量

文章是关于AlGaN/GaN HEMTs&#xff08;高电子迁移率晶体管&#xff09;在不同基底&#xff08;如蓝宝石和硅&#xff09;上生长时&#xff0c;通过直流&#xff08;DC&#xff09;特性方法确定沟道温度的研究。文章由J. Kuzmk, P. Javorka, A. Alam, M. Marso, M. Heuken, 和 …

微软如何打造数字零售力航母系列科普04 - 微软联合Adobe在微软365应用程序中工作时推出新的生成式AI功能

微软和Adobe正在合作&#xff0c;将情境营销见解和工作流程引入微软Copilot&#xff0c;以提供生成的人工智能功能&#xff0c;使营销人员和营销团队能够在自然的工作流程中实现更多目标。 这些新的集成功能将在生产力和协作工具&#xff08;如Outlook、Teams和Word&#xff0…

JAVA基础——集合框架(List与Set)

数据结构 什么是数据结构 数据结构就是用来装数据以及数据与之间关系的一种集合。如何把相关联的数据存储到计算机&#xff0c;为后续的分析提供有效的数据源&#xff0c;是数据结构产生的由来。数据结构就是计算机存储、组织数据的方式。好的数据结构&#xff0c;让我们做起事…

使用QT完成如图的游戏登录界面 使用信号和槽完成密文明文密码转换,重置账号和密码,登录校验 详细代码在主页下载

头文件: #ifndef LOGINWIDGET_H #define LOGINWIDGET_H #include <QLineEdit> #include <QPushButton> #include <QWidget> class LoginWidget : public QWidget {Q_OBJECT public: LoginWidget(QWidget *parent = 0); ~LoginWidget(); public slots: …

基于uniapp+微信小程序的智能停车场管理小程序,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Three.js杂记(十五)—— 汽车展览(下)

在上一篇文章Three.js杂记&#xff08;十四&#xff09;—— 汽车展览上 - 掘金 (juejin.cn)中主要对切换相机不同位置和鼠标拖拽移动相机焦点做了简单的应用。 那么现在聊聊该如何实现汽车模型自带的三种动画展示了&#xff0c;实际上可以是两种汽车前后盖打开和汽车4车门打开…

C# APS.NET CORE 6.0 WebApi在IIS部署报错

今天尝试着把基于 APS.NET CORE6.0开发的webAPI程序部署到IIS中&#xff0c;当打开网站地址时报错&#xff0c;无法打开&#xff0c;于是查找资料最终进行了解决。 打开 IIS →模块 查看列表中是否存在 AspNetCoreModuleV2&#xff0c;如下&#xff1a; 对应的应用池需要选择“…

小程序SSL证书更新指南

随着网络技术的不断发展&#xff0c;小程序已经成为许多企业和个人进行业务推广和服务提供的重要平台。在享受小程序带来的便利和高效的同时&#xff0c;我们也必须重视其安全性问题。SSL证书作为保障小程序数据传输安全的重要手段&#xff0c;其更新工作不容忽视。本文将为大家…

Android log tag标签如am_pss意义

Android log tag标签如am_pss意义 Android输出日志中不同的标签代表不同的意义&#xff0c;比如 am_pss&#xff0c;则代表内存回收&#xff08;整理&#xff09;。定义在源代码文件 &#xff1a; https://android.googlesource.com/platform/frameworks/base//master/servic…

字节5面挂,恶心到了。。。

字节五面 今天脉脉看到一篇帖子&#xff1a; 楼主是 tx 的前员工&#xff0c;在字节五面&#xff08;加轮&#xff09;被挂后&#xff0c;认定&#xff08;或许私下做了一些调查&#xff09;是字节 HR 向 tx 背调&#xff0c;然后被前同事捏造虚假信息&#xff0c;导致的面试失…

初识MVC

初识MVC 理论部分 今天第一次学MVC&#xff0c;拿到一个练手项目。现在来记录一下学习过程。 项目的背景就是个学生管理系统。我只做后端。 从大的来说MVC将应用程序分为三个主要组件&#xff08;部分&#xff09;&#xff1a; 模型&#xff08;Model&#xff09;是应用程序…

UE5像素流部署以及多实例部署(兼容ue4)

像素流部署请看我之前的文章就行&#xff0c;今天讲的是多实例部署 在这里可以配置多实例的数量 如果设置800端口 设置两个实例 那么就是800 801端口 我的个人显卡是4060TI,最多开三个

张大哥笔记:服务器有挖矿木马程序,该如何处理?

这篇文章发表于2021年&#xff0c;今天借这个平台再发布一下&#xff0c;希望对大家有所帮助&#xff01; 今天收到一个粉丝求助&#xff0c;说收到了阿里云官方短信通知提示有挖矿程序&#xff0c;要求立即整改&#xff0c;否则会关停服务器&#xff0c;以下是我和他的对话内…

238 基于matlab的水平轰炸弹道的求解

基于matlab的水平轰炸弹道的求解&#xff0c;列出轰炸弹道方程组并利用龙格库塔法解算弹道方程。设计中包含了二维弹道与三维弹道的计算&#xff0c;并都绘制了弹道运动轨迹&#xff0c;最终还将整个题目集中在一个图形用户界面&#xff08;GUI&#xff09;上。程序已调通&…

CTFHub-Web-SSRF

CTFHub-Web-SSRF-WP 一、内网访问 1.题目提示说访问127.0.0.1的flag.php&#xff0c;在URL后面添加路径没想到直接访问成功 二、伪协议读取文件 1.题目提示说访问Web目录下的flag.php&#xff0c;联想到Web目录一般存放于/var/www/html/里&#xff0c;去修改URL尝试进行访问…

Atlassian Jira 信息泄露漏洞(CVE-2019-3403) 排查思路

Atlassian Jira&#xff1a; 企业广泛使用的项目与事务跟踪工具&#xff0c;被广泛应用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪和敏捷管理等工作领域。 简述&#xff1a; 近日发现多个内网IP触发的Atlassian Jira 信息泄露漏洞的告警。 告警的检测规…

机器学习之基于Tensorflow(LSTM)进行多变量时间序列预测股价

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 项目简介&#xff1a;机器学习之基于TensorFlow&#xff08;LSTM&#xff09;进行多变量时间序列预测股价 一、项目…

Django-基础篇

Django是一个开放源代码的Web应用框架&#xff0c;由Python语言编写。它遵循MVC&#xff08;Model-View-Controller&#xff09;的软件设计模式&#xff0c;使开发者能够以高效、可扩展和安全的方式构建Web应用程序。 Django具有以下特点和优势&#xff1a; 强大的功能&#x…