为了账号安全,请及时绑定邮箱和手机立即绑定

React 19 新特性详解与实战教程

标签:
JavaScript React

React 19带来了许多令人兴奋的新功能和性能改进。本教程将详细介绍 React 19 的核心新特性,并通过实际代码案例帮助您快速上手。

1. React 19 概览

React 19 的重点在于提升开发体验(DX)、性能和对现代 Web 应用复杂性的支持。它引入了几个旨在简化常见模式(如表单处理、乐观更新)的 API。


2. Action & State (useActionState)

useActionState 是一个全新的 Hook,旨在将一个异步的 "action" 函数与一个状态变量绑定在一起。它特别适用于表单提交,可以让你轻松地获取 action 的返回值作为组件的状态,并且内置了对 pending 状态的支持。

旧方式:

import { useState } from 'react';

// 一个典型的 action 函数
async function addToCart(productId) {
  // 模拟 API 调用
  await new Promise(resolve => setTimeout(resolve, 1000));
  return { success: true, message: `Added product ${productId} to cart!`, timestamp: Date.now() };
}

function AddToCartButton({ productId }) {
  const [isPending, setIsPending] = useState(false);
  const [lastResult, setLastResult] = useState(null);

  const handleAddToCart = async () => {
    setIsPending(true);
    try {
      const result = await addToCart(productId);
      setLastResult(result);
    } finally {
      setIsPending(false);
    }
  };

  return (
    <>
      <button onClick={handleAddToCart} disabled={isPending}>
        {isPending ? 'Adding...' : 'Add to Cart'}
      </button>
      {lastResult && <p>Last result: {lastResult.message}</p>}
    </>
  );
}

React 19 新方式 (useActionState):

import { useActionState } from 'react';
import { addToCart } from './actions'; // 假设 action 函数在此处定义

function AddToCartButton({ productId }) {
  const [state, formAction, isPending] = useActionState(addToCart, null);

  return (
    <form action={formAction}>
      {/* 通过隐藏字段将 productId 传递给 action */}
      <input type="hidden" name="productId" value={productId} />
      <button type="submit" disabled={isPending}>
        {isPending ? 'Adding...' : 'Add to Cart'}
      </button>
      {state && <p>Last result: {state.message}</p>}
    </form>
  );
}

useActionState 让表单逻辑更加简洁和声明式。


3. useOptimistic - 乐观 UI 更新

乐观 UI 是一种提升用户体验的技术,即在等待服务器确认之前,先假设操作会成功,并立即更新 UI。useOptimistic Hook 为此提供了一流的支持。

案例:一个简单的评论列表

import { useState, useOptimistic } from 'react';

function CommentSection() {
  const [comments, setComments] = useState([
    { id: 1, text: 'Great post!' },
    { id: 2, text: 'Thanks for sharing.' }
  ]);
  const [optimisticComments, addOptimisticComment] = useOptimistic(
    comments,
    (state, newComment) => [...state, {id: Date.now(), text: newComment, optimistic: true }]
  );

  const handleSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);
    const newCommentText = formData.get('comment');

    // 先更新乐观 UI
    addOptimisticComment(newCommentText);

    try {
      // 模拟发送到服务器
      await new Promise(resolve => setTimeout(resolve, 1000));
      // 成功后,更新真实状态
      setComments(c => [...c, { id: Date.now(), text: newCommentText }]);
    } catch (e) {
      // 如果失败,需要手动恢复 UI
      console.error("Failed to submit comment", e);
      // ... 恢复逻辑 ...
    }
  };

  return (
    <div>
      <h3>Comments</h3>
      <ul>
        {optimisticComments.map(comment => (
          <li key={comment.id} style={{ opacity: comment.optimistic ? 0.6 : 1 }}>
            {comment.text} {comment.optimistic ? '(Sending...)' : ''}
          </li>
        ))}
      </ul>
      <form onSubmit={handleSubmit}>
        <input type="text" name="comment" placeholder="Write a comment..." required />
        <button type="submit">Post</button>
      </form>
    </div>
  );
}

在这个例子中,用户提交评论后,列表会立刻显示新评论(带有淡化的样式表示它是乐观的),而不会等待服务器响应,大大提升了响应感。


4. Ref 改进 (useRef)

React 19 中,useRef 的行为变得更加一致和强大。现在,你可以安全地将 ref.current 设置为 nullundefined,而不会触发错误。更重要的是,useRef 现在可以接受一个函数作为初始值,该函数仅在 ref 被创建时调用一次。

新语法示例:

import { useRef, useEffect } from 'react';

function MyComponent() {
  // 1. 可以安全地设置为 null
  const nullableRef = useRef();
  useEffect(() => {
    // 一些操作...
    nullableRef.current = null; // 这在以前可能导致问题
  }, []);

  // 2. 函数式初始化 (惰性初始化)
  const expensiveValueRef = useRef(() => {
    // 这个函数只在组件首次挂载时执行一次
    console.log("Expensive calculation running...");
    return performExpensiveCalculation(); // 假设这是一个昂贵的操作
  });

  return <div ref={nullableRef}>My Component</div>;
}

5. Form Actions 的增强

React 19 极大地增强了对 HTML <form> 元素的支持,使其与新的 useActionStateuseOptimistic 等 Hook 配合得更好。<form> 现在可以接受一个 JavaScript 函数作为 action prop,而不是仅仅是一个 URL。

示例:

import { useActionState, useOptimistic } from 'react';

// 一个更新用户信息的 action
async function updateProfile(prevState, formData) {
  const name = formData.get('name');
  const email = formData.get('email');
  // ... 调用 API
  await new Promise(resolve => setTimeout(resolve, 500)); // 模拟延迟
  return { success: true, message: `Updated profile for ${name}` };
}

function ProfileForm() {
  const [state, formAction] = useActionState(updateProfile, null);

  return (
    <form action={formAction}>
      <label htmlFor="name">Name:</label>
      <input id="name" name="name" type="text" required />

      <label htmlFor="email">Email:</label>
      <input id="email" name="email" type="email" required />

      <button type="submit">Update Profile</button>
      {state?.message && <p>{state.message}</p>}
    </form>
  );
}

6. 错误边界与 Suspense 的改进

React 19 修复了一些关于错误边界和 Suspense 的边缘案例,并使它们的行为更加可预测。特别是,错误边界现在可以捕获在同一个渲染通道中由 Suspense fallback 引发的错误。


7. 其他值得注意的变更

  • <script><link> 组件: 在服务端渲染(SSR)时,React 现在会自动优化 <script><link> 标签的注入,减少了客户端 hydration 不匹配的风险。
  • 组件返回值: 组件不再能返回 undefined。如果一个组件需要有条件地不渲染任何内容,它必须显式返回 null
  • 性能: 内部实现进行了优化,提高了整体性能。

8. 实战案例:构建一个待办事项列表

让我们将学到的知识结合起来,创建一个带有乐观 UI 和表单提交的待办事项应用。

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

// 模拟 API 调用
async function addTodo(formData) {
  const text = formData.get('todo');
  await new Promise(resolve => setTimeout(resolve, 500));
  return { id: Date.now(), text, completed: false }; // 模拟返回新创建的 todo
}

function TodoApp() {
  const [todos, setTodos] = useState([]);
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, { id: Date.now(), text: newTodo, completed: false, optimistic: true }]
  );

  const [state, formAction] = useActionState(async (prevState, formData) => {
    const newTodo = await addTodo(formData);
    setTodos(t => [...t, newTodo]);
    return null;
  }, null);

  const toggleTodo = (id) => {
    setTodos(currentTodos =>
      currentTodos.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  return (
    <div>
      <h1>My Todo List</h1>
      <form action={formAction}>
        <input name="todo" placeholder="What needs to be done?" required />
        <button type="submit">Add Todo</button>
      </form>
      <ul>
        {optimisticTodos.map(todo => (
          <li 
            key={todo.id} 
            style={{ 
              textDecoration: todo.completed ? 'line-through' : 'none',
              opacity: todo.optimistic ? 0.6 : 1
            }}
          >
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
            />
            {todo.text} {todo.optimistic ? '(Adding...)' : ''}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoApp;

这个案例展示了 useOptimistic 如何让添加待办事项的体验变得流畅,以及 useActionState 如何简化表单提交的逻辑。


总结

React 19 通过引入 useActionStateuseOptimistic 等新 Hook,显著简化了常见的 UI 模式,如表单处理和乐观更新。同时,对 Refs 和 Form Actions 的改进也提升了开发体验和应用的健壮性。拥抱这些新特性,可以让您的 React 应用更加高效和用户友好。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 2
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消