目录

【前端风向标】第二期-React 19 新特性洞察

作者:黄轩 openInula核心贡献者/架构SIG成员

新增

use

use作为React19更新感知最明显的变化,其主要作用是获取异步数据,use可以用来读取context,promise对象。且与Hooks不同,use可以被有条件地调用 。React社区未来计划支持在渲染中使用use的更多方式

tsx 复制代码
import {use} from 'react';

function Comments({commentsPromise}) {
	// `use` will suspend until the promise resolves.
	const comments = use(commentsPromise);
	return comments.map(comment => <p key={comment.id}>{comment}</p>);
}

function Page({commentsPromise}) {
	// When `use` suspends in Comments,
	// this Suspense boundary will be shown.
	return (
		<Suspense fallback={<div>Loading...</div>}>
			<Comments commentsPromise={commentsPromise} />
		</Suspense>
	)
}

use不支持在渲染中创建的Promise

tsx 复制代码
function Comments({commentsPromise}) {
	const fetchData = new Promise<string>(resolve => setTimeout(() => resolve('Hello React19')));
	const comments = use(commentsPromise);
	return comments.map(comment => <p key={comment.id}>{comment}</p>);
}

useOptimistic

乐观更新

是一种在用户界面(UI)和数据交互场景中使用的策略,主要用于提升用户体验。在许多应用程序中,当用户执行一个操作(如提交表单、添加或删除数据项等)时,通常需要向服务器发送请求来更新数据。传统的方式是等待服务器响应后再更新 UI。而乐观更新则是在发送请求的同时,假设服务器会成功处理这个请求,立即更新 UI 来反映这个变化。

使用场景
  • 购物车应用添加商品:用户将商品添加到购物车时,购物车中的商品数量和总价会立刻更新,好像商品已经成功添加到购物车一样。随后服务器会验证这个添加操作是否合法(例如商品是否有库存、用户是否登录等)。如果服务器验证成功,这个更新就保持;如果失败,购物车的数量和总价会回滚到之前的状态。
  • 即使通讯软件中发送消息:当用户发送一条消息时,消息会立即出现在聊天窗口的发送框下方,并且显示为 "已发送" 状态。这是一种乐观更新,因为软件假设消息能够成功发送到服务器并被接收方获取。
示例
tsx 复制代码
function Thread({ messages, sendMessage }) {
  const formRef = useRef();
  async function formAction(formData) {
    addOptimisticMessage(formData.get("message"));
    formRef.current.reset();
    await sendMessage(formData);
  }
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [
      ...state,
      {
        text: newMessage,
        sending: true
      }
    ]
  );

  return (
    <>
      {optimisticMessages.map((message, index) => (
        <div key={index}>
          {message.text}
          {!!message.sending && <small> (Sending...)</small>}
        </div>
      ))}
      <form action={formAction} ref={formRef}>
        <input type="text" name="message" placeholder="Hello!" />
        <button type="submit">Send</button>
      </form>
    </>
  );
}

export default function App() {
  const [messages, setMessages] = useState([
    { text: "Hello there!", sending: false, key: 1 }
  ]);
  async function sendMessage(formData) {
    const sentMessage = await deliverMessage(formData.get("message"));
    setMessages((messages) => [...messages, { text: sentMessage }]);
  }
  return <Thread messages={messages} sendMessage={sendMessage} />;
}

当请求完成后optimisticMessages的值会被更新为messages,请求失败时optimisticMessages会回退到未更新的messages

useActionState

useActionState 是一个可以根据某个表单动作的结果更新 state 的 Hook,返回的action需要在<form>标签中触发

tsx 复制代码
async function add(payload: { value: number }) {
  return new Promise<{ value: number }>(resolve => {
    setTimeout(() => {
      resolve({ value: payload.value + 1 });
    }, 2000);
  });
}

function useActionStateDemo() {
  const [state, action, isPending] = useActionState<{ value: number }>(add, { value: 0 });

  return (
    <form>
      {isPending ? 'working' : <div>{state.value}</div>}
      <button formAction={action}>plus value</button>
    </form>
  );
}

注意 该Hook在React19 RC中的名称为useFormState

变更

ref

refprop支持传入清理函数,当组件卸载时,React 将调用从 ref 回调返回的清理函数。这适用于 DOM refs,类组件的 refs,以及 useImperativeHandle

tsx 复制代码
<input ref={(ref)=>{ 
	// xxx
	return ()=>{
		// ref clean
	}
}}>

注意 在React19之前的版本,卸载组件时ref会被置为null,现在如果提供了清理函数,React将不再会将ref置为null

注意:Ref函数中的隐式返回可能导致问题

diff 复制代码
- <div ref={current => (instance = current)} />
+ <div ref={current => {instance = current}} />

Context

<Context>可以直接作为渲染提供者,无需使用<Context.Provider> 在未来的版本中会废弃<Context.Provider>的写法

forwardRef

React19中函数式组件可以直接使用Ref,不再需要forwardRef函数

  • Befor
tsx 复制代码
const MyInput = forwardRef(function ({ placeholder }, ref) {
  return <input placeholder={placeholder} ref={ref} />;
});
  • Now
tsx 复制代码
const MyInput = ({placeholder, ref}) => {
	return <input placeholder={placeholder} ref={ref}>
}

在未来的版本中forwardRef函数会废弃

useDeferredValue

React19支持useDeferredValue传入第二个参数initialValue,函数签名如下

typescript 复制代码
export function useDeferredValue<T>(value: T, initialValue?: T): T;

使用该参数useDeferredValue在首次渲染就可以延迟

useTransition

useTransition支持异步函数

await之后的状态不会视为Transition

tsx 复制代码
startTransition(async () => {
	await someAsyncFunction();
	// ❌ 不要在 await 之后调用 startTransition
	setPage('/about');
});
tsx 复制代码
startTransition(async () => {
	await someAsyncFunction();
	// ✅ await之后再使用Transition
	startTransition(() => {
		setPage('/about');
	});
});

移除

  • string Refs
  • getChildContextcontextTypes

ReactDOM

新增

<form> Action

在 React 19 中,Actions 与 react-dom 的新 <form> 特性进行了整合。现在,可以将函数作为<form><input><button>元素的action和formAction属性,以便自动使用 Actions 提交表单:

tsx 复制代码
<input action={action}/>

<form>的action成功执行时,React会自动为不受控组件重置表单状态。如果需要手动重置<form>,React DOM API 提供了全新的requestFormReset方法。

useFormStatus

用于获取上次表单提交状态信息 const { pending, data, method, action } = useFormStatus();

  • pending:布尔值。如果为 true,则表示父级 <form> 正在等待提交;否则为 false

  • data:实现了 FormData interface 的对象,包含父级 <form> 正在提交的数据;如果没有进行提交或没有父级 <form>,它将为 null

  • method:字符串,可以是 'get''post'。表示父级 <form> 使用 GETPOST HTTP 方法 进行提交。默认情况下,<form> 将使用 GET 方法,并可以通过 method 属性指定。

  • action:一个传递给父级 <form>action 属性的函数引用。如果没有父级 <form>,则该属性为 null。如果在 action 属性上提供了 URI 值,或者未指定 action 属性,status.action 将为 null

注意 该Hook只能在位于<form>标签之下的函数式组件中使用

移除

  • unmountComponentAtNode
  • ReactDOM.findDOMNode
  • ReactDOM.render
  • ReactDOM.hydrate
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
学不动学不明白几秒前
PC端项目兼容手机端
前端
无名之逆几秒前
Hyperlane:轻量、高效、安全的 Rust Web 框架新选择
开发语言·前端·后端·安全·rust·github·ssl
wkj0017 分钟前
js给后端发送请求的方式有哪些
开发语言·前端·javascript
最新资讯动态14 分钟前
“RdbStore”上线开源鸿蒙社区 助力鸿蒙应用数据访问效率大幅提升
前端
magic 24515 分钟前
JavaScript运算符与流程控制详解
开发语言·前端·javascript
xulihang40 分钟前
在手机浏览器上扫描文档并打印
前端·javascript·图像识别
RR91 小时前
【Vue3 进阶👍】:如何批量导出子组件的属性和方法?从手动代理到Proxy的完整指南
前端·vue.js
加个鸡腿儿1 小时前
01实战案例:「新手向」如何将原始数据转换为前端可用选项?
前端·程序员
java1234_小锋1 小时前
一周学会Flask3 Python Web开发-SQLAlchemy更新数据操作-班级模块
前端·数据库·python·flask·flask3
一个爱挣扎的旺崽1 小时前
【echarts图例模糊】解决
前端·echarts