新React v19特性

devtools/2024/10/18 19:27:39/

服务器组件(RSC):经过多年的开发,React 引入了服务器组件,而不是需要借助Next.js

动作(Action):Action也将彻底改变我们与 DOM 元素的交互方式。

增强的 hooks:引入了很多新 hooks,将改变我们的编码体验。

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

  • 一个 Actions
  • 三个新 hook
  • 一个新 API
  • ref 和 context 用法更方便
  • 其他支撑类更新、服务端能力更新

1.如何使用服务器组件

默认情况下,React中的所有组件都是客户端组件。只有使用 'use server'` 时,组件才是服务器组件。

我们只需要将 'use server' 添加为组件的第一行即可。这将使组件成为服务器组件。它不会在客户端运行,只会在服务器端运行。

'use server';export default async function requestUsername(formData) {const username = formData.get('username');if (canRequest(username)) {// ...return 'successful';}return 'failed';
}

2.动作(Action

什么是Action

使用异步转换的函数被称为Action(动作)。Action自动管理数据的提交:

  1. Pending状态:Action 提供了一个 state
    • 请求开始时,代表对应的状态 -pending状态
    • 请求结束时,状态自动重置
  1. Optimistic更新:Action支持新的useOptimistichook,因此我们可以在请求提交时向用户显示即时反馈。
  1. 错误处理:Action提供错误处理,因此我们可以在请求失败时显示Error Boundary,并自动恢复Optimistic更新为其原始值。
  1. 增强表单操作:
  1. 元素支持将函数传递给 action 和 formAction props。
    • 传递给action props的函数默认使用Action机制,并在提交后自动重置表单

Action将允许我们将action<form/>标签 集成。简单来说,我们将能够用action替换 onSubmit 事件。

在使用Action之前

在下面的代码片段中,利用 onSubmit事件,在表单提交时触发搜索操作。

<form onSubmit={search}><input name="query" /><button type="submit">查询</button>
</form>

使用Action之后

随着服务器组件的引入, Action可以在服务器端执行。在 JSX 中,我们可以删除 <form/>onSubmit 事件,并使用 action 属性。action 属性的值将是一个提交数据的方法,可以在客户端服务器端提交数据。

我们可以使用Action执行同步异步操作,简化数据提交管理和状态更新。为的是使处理表单和数据更加容易。

"use server"const submitData = async (userData) => {const newUser = {username: userData.get('username'),email: userData.get('email')}console.log(newUser)
}
const Form = () => {return <form action={submitData}><div><label>用户名</label><input type="text" name='username'/></div><div><label>邮箱</label><input type="text" name="email" /></div><button type='submit'>提交</button></form>
}export default Form;

在上面的代码中,submitData 是服务器组件中的Actionform 是一个客户端组件,它使用 submitData 作为ActionsubmitData 将在服务器上执行。

3.Hooks

React 19 中,我们使用 useMemoforwardRefuseEffectuseContext 的方式将会改变。这主要是因为将引入一个新的 hook,即 use

useMemo()

之前的写法

import React, { useState, useMemo } from 'react';function ExampleComponent() {const [inputValue, setInputValue] = useState('');// 记住输入框是否为空的检查结果const isInputEmpty = useMemo(() => {console.log('检测输入框是否为空');return inputValue.trim() === '';}, [inputValue]);return (<div><inputtype="text"value={inputValue}onChange={(e) => setInputValue(e.target.value)}/><p>{isInputEmpty ? 'Input 为空' : 'Input有值'}</p></div>);
}export default ExampleComponent;

之后的写法

import React, { useState } from 'react';function ExampleComponent() {const [inputValue, setInputValue] = useState('');const isInputEmpty = () => {console.log('检测输入框是否为空');return inputValue.trim() === '';});return (<div><inputtype="text"value={inputValue}onChange={(e) => setInputValue(e.target.value)}/><p>{isInputEmpty ? 'Input 为空' : 'Input有值'}</p></div>);
}export default ExampleComponent;

我们可以看到在 React19 之后,我们不再需要自己来做记忆化,React19 将会在后台自动完成。

forwardRef()

ref 现在将作为props传递而不是使用 forwardRef() hook。

这将简化代码。因此,在 React19 之后,我们不需要使用 forwardRef()

之前的写法

import React, { forwardRef } from 'react';const ExampleButton = forwardRef((props, ref) => (<button ref={ref}>{props.children}</button>
));

之后的写法

ref 可以作为属性传递。不再需要 forwardRef()

import React from 'react';const ExampleButton = ({ ref, children }) => (<button ref={ref}>{children}</button>
);

新的 use() hook

这个 hook 将简化我们如何使用 promisesasync 代码和 context

const value = use(resource);

示例1:接收async函数

下面的代码是使用 use hook 进行 fetch 请求的示例:

import { use } from "react";const fetchUsers = async () => {const res = await fetch("远程地址");return res.json();};const UsersItems = () => {const users = use(fetchUsers());return (<ul>{users.map((user) => (<div key={user.id} ><h2>{user.name}</h2><p>{user.email}</p></div>))}</ul>);
}; 
export default UsersItems;
  • fetchUsers进行远程数据请求
  • 我们使用usehook 执行fetchUsers,而不是使用useEffectuseStatehooks。
  • usehook 的返回值是users,其中包含GET请求的响应(users)。
  • return中,我们使用users进行对应信息的渲染处理。

示例2:接收context对象

我们以后可以直接将context对象传人到use()中,从而达到将context引入组件的目的。而不需要useContext()了。

使用createContext定义全局变量

这里我们定义

import { createContext, useState, use } from 'react';const ThemeContext = createContext();const ThemeProvider = ({ children }) => {const [theme, setTheme] = useState('light');const toggleTheme = () => {setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));};return (<ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>);
};
在组件中使用use()获取context信息
const Card = () => {// use Hook()const { theme, toggleTheme } = use(ThemeContext);return (// 基于theme/toggleTheme 渲染页面或者执行对应的操作);
};const Theme = () => {return (<ThemeProvider><Card /></ThemeProvider>);
};export default Theme

上面代码中有几点需要简单解释一下:

  • ThemeProvider负责提供context
  • Card是我们将消费context的组件。为此,我们将使用新的 hookuse来消费context

useFormStatus() hook

React19 中,我们还有新的 hooks 来处理表单状态数据。这将使处理表单更加流畅和简单。将这些 hooksAction结合使用将使处理表单和数据更加容易。

React19 中的这个新 hook 将帮助我们更好地控制你创建的表单。它将提供关于上次表单提交的状态信息。

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

基础语法

这是它的语法:

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

或者简化的版本:

const { status } = useFormStatus()
  • pending:如果表单处于待处理状态,则为true,否则为false
  • data:一个实现了FormData接口的对象,其中包含父<form>提交的数据。
  • method:HTTP方法 – GET,或 POST。
    • 默认情况下将是 GET。
  • action:一个函数引用。

案例展示

useFormStatus是从react-dom库中导出的

import { useFormStatus } from "react-dom";function Submit() {const status = useFormStatus();return <button disabled={status.pending}>{status.pending ? '正在提交...' : '提交完成'}</button>;
}// ==== 父组件 ==引入Submit ====const formAction = async () => {// 模拟延迟 3 秒await new Promise((resolve) => setTimeout(resolve, 3000));
}const FormStatus = () => {return (<form action={formAction}><Submit /></form>);
};export default FormStatus;

解释一下:

  • Submit通过useFormStatus可以获取此时from表单的提交状态,并基于一些状态渲染一些辅助信息
  • formAction是执行异步提交的处理

在上面的代码中,当表单提交时,从 useFormStatus hook 我们将获得一个 pending 状态。

  • pendingtrue时,UI 上会显示 "正在提交..." 文本。
  • 一旦pendingfalse,"正在提交..." 文本将被更改为 "提交完成"。

当我们想要知道表单提交的状态并相应地显示数据时,它会很有用。

useFormState() hook

React19 中的另一个新 hook 是 useFormState。它允许我们根据表单提交的结果来更新状态。

语法

这是它的语法:

const [state, formAction] = useFormState(fn, initialState, permalink?);
  • fn:表单提交或按钮按下时要调用的函数。
  • initialState:我们希望状态初始值是什么。它可以是任何可序列化的值。在首次调用操作后,此参数将被忽略。
  • permalink:这是可选的。一个URL或页面链接,如果fn将在服务器上运行,则页面将重定向到permalink

这个 hook 将返回:

  • state:初始状态将是我们传递给initialState的值。
  • formAction:一个将传递给表单操作的操作。此操作的返回值将在状态中可用。

案例展示

import { useFormState} from 'react-dom';const FormState = () => {const submitForm = (prevState, queryData) => {const name =  queryData.get("username");console.log(prevState); // 上一次的from 的state if(name === '柒八九'){return {success: true,text: "前端开发者"}}else{return {success: false,text: "Error"}}}const [ message, formAction ] = useFormState(submitForm, null)return <form action={formAction}><label>用户名</label><input type="text" name="username" /><button>提交</button>{message && <h1>{message.text}</h1>}</form>
}export default FormState;

解释一下

  • submitForm是负责表单提交的方法。这是一个Action
  • 在 submitForm中,我们正在检查表单的值。
    • prevState:初始状态将为null,之后它将返回表单的prevState
    • queryData:用于获取此次操作中from表单中对应key的值

useOptimistic() hook

useOptimistic – React 中文文档

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

这个 hook 将帮助增强用户体验,并应该导致更快的响应。这对于需要与服务器交互的应用程序非常有用。

语法

以下是 useOptimistic hook 的语法:

const [ optimisticX, addOptimisticX] = useOptimistic(state, updatefn)

例如,当响应正在返回时,我们可以显示一个optimistic状态,以便让用户获得即时响应。一旦服务器返回实际响应,optimistic状态将被替换。

import { useOptimistic } from 'react';function AppContainer() {const [optimisticState, addOptimistic] = useOptimistic(state,// 更新函数(currentState, optimisticValue) => {// 使用乐观值// 合并并返回新 state});
}

其中:

这个状态被称为“乐观”状态是因为通常用于立即向用户呈现执行操作的结果,即使实际上操作需要一些时间来完成

参数

  • state:初始时和没有挂起操作时要返回的值。
  • updateFn(currentState, optimisticValue):一个函数,接受当前 state 和传递给 addOptimistic 的乐观值,并返回结果乐观状态。它必须是一个纯函数。updateFn 接受两个参数:currentState 和 optimisticValue。返回值将是 currentState 和 optimisticValue 的合并值。

返回值

  • optimisticState:结果乐观状态。除非有操作挂起,否则它等于 state,在这种情况下,它等于 updateFn 返回的值。
  • addOptimistic:触发乐观更新时调用的 dispatch 函数。它接受一个可以是任何类型的参数 optimisticValue,并以 state 和 optimisticValue 作为参数来调用 updateFn。


http://www.ppmy.cn/devtools/118114.html

相关文章

社团周报系统可行性研究-web后端框架对比-springboot,django,gin

对于目前市面上web后端框架&#xff0c;我主要了解到的就是springboot&#xff0c;django gin等&#xff0c;分别对应java python go三种语言&#xff0c;目前我比较熟悉的就是springboot 目录 spring boot框架 简介 优点 缺点 适用场景 与需求匹配度 django框架 简介…

商城小程序源码搭建部署,商城购物小程序开发流程(php框架)

关于商城小程序 商城小程序作为一种基于移动互联网的在线购物平台&#xff0c;商家可以上架所销售的产品&#xff0c;定价&#xff0c;以及营运营的在线售货平台。买家无需下载应用&#xff0c;在小程序搜索打开即可浏览下单商品。 技术栈 前端: vue uniapp 后端&#xff1a…

探索甘肃非遗:Spring Boot网站开发案例

1 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。这样的大环境让那些止步不前&#…

【漏洞复现】公交IC卡收单管理系统 SQL注入致RCE漏洞复现

》》》产品描述《《《 公交IC卡收单 管理系统Q是城市公共交通领域中不可或缺的一部分&#xff0c;它通过集成先进的集成电路技术(IC卡)实现了乘客便捷的支付方式&#xff0c;并有效提高了公共交通运营效率。系统集成了发卡、充值、消费、数据采集、查询和注销等多个功能模块&am…

再谈智慧园区

随着AI的兴起&#xff0c;其影响力将渗透到各行各业。产业园区也不例外。特别是江园科技智慧园区在园区运营上&#xff0c;从早期的信息化&#xff0c;到数字化、智能化&#xff0c;智慧园区是一个不可回避的话题。 01 江园科技智慧园区 无论名称或概念怎么办&#xff0c;产…

正则表达式的使用示例--Everything文件检索批量重命名工具

一、引言 Everything是一款非常实用的文件搜索工具&#xff0c;它可以帮助您快速定位并查找计算机中的文件和文件夹。Everything搜索文件资料之神速&#xff0c;有使用过的朋友们都深有体会&#xff0c;相对于Windows自带的搜索功能&#xff0c;使用Everything&#xff0c;可以…

C++学习笔记(35)

四十三、希尔排序 示例&#xff1a; #include <iostream> using namespace std; // 对希尔排序中的单个组进行排序。 // arr-待排序的数组&#xff0c;len-数组总的长度&#xff0c;num-小组的编号&#xff08;从 0 开始&#xff09;&#xff0c;step-分组的步长&#xf…

cpp中的namespace详解

namespace的作用主要是为了避免名字冲突和组织代码。 命名空间在C中是一个非常重要的特性&#xff0c;它帮助开发者更好地管理代码和避免潜在的冲突。 具体来说&#xff0c;它有以下几个主要用途 避免名字冲突 在大型项目中可能会有很多个类、函数或变量使用相同的名称。使用…