+14

React 19 Beta đã được phát hành!

1. Giới thiệu

React 19 Beta hiện có sẵn trên npm! Trong bài đăng này, mình sẽ cung cấp cái nhìn tổng quan về các tính năng mới trong React 19 và cách có thể áp dụng sử dụng nó. react-beta

2. Có gì mới trong React 19

2.1 Actions

Một trường hợp sử dụng phổ biến trong các ứng dụng React là thực hiện một sự thay đổi data và sau đó cập nhật state trong response. Ví dụ, khi một người dùng gửi một biểu mẫu để thay đổi tên của họ, bạn sẽ thực hiện một yêu cầu API, sau đó xử lý response. Trước đây, bạn sẽ cần phải xử lý states pending, error, success và các yêu cầu tuần tự một cách thủ công. Ví dụ, bạn có thể xử lý trạng thái pending và error trong useState():

// Before Actions
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>
  );
}

Trong React 19, có thêm hỗ trợ cho việc sử dụng các function async trong các transitions để xử lý các pending states, errors, forms và cập nhật tự động. Ví dụ, bạn có thể sử dụng useTransition()để xử lý pending state cho bạn:

// Using pending state from Actions
function UpdateName({}) {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, startTransition] = useTransition();

  const handleSubmit = () => {
    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>
  );
}

Ví dụ trên, async transition sẽ ngay lập tức đặt trạng thái isPending là true, thực hiện các yêu cầu async và chuyển đổi isPending thành false sau bất kì transitions nào. Điều này cho phép bạn giữ UI responsive và tương tác trong khi dữ liệu đang thay đổi.

React 19 giới thiệu thêm useOptimistic để quản lý cập nhật optimistic, và một hook mới là React.useActionState để xử lý các trường hợp phổ biến cho Actions. Trong react-dom, đang thêm form Actions để quản lý form tự động và useFormStatus để hỗ trợ các trường hợp phổ biến cho Actions trong forms.

Trong React 19, ví dụ trên có thể được đơn giản hóa thành:

// Using <form> Actions and useActionState
function ChangeName({ name, setName }) {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const error = await updateName(formData.get("name"));
      if (error) {
        return error;
      }
      redirect("/path");
      return null;
    },
    null,
  );

  return (
    <form action={submitAction}>
      <input type="text" name="name" />
      <button type="submit" disabled={isPending}>Update</button>
      {error && <p>{error}</p>}
    </form>
  );
}

2.2 New hook: useActionState

Để làm cho các trường hợp phổ biến dễ dàng hơn đối với Actions, React 19 đã thêm một hook mới có tên useActionState:

const [error, submitAction, isPending] = useActionState(
  async (previousState, newName) => {
    const error = await updateName(newName);
    if (error) {
      // You can return any result of the action.
      // Here, we return only the error.
      return error;
    }

    // handle success
    return null;
  },
  null,
);

useActionState chấp nhận một function (gọi là "Action"), và trả về một Action được bọc để gọi. Điều này hoạt động vì Actions có thể compose. Khi Action được bọc được gọi, useActionState sẽ trả về kết quả cuối cùng của Action như là data, pending state của Action. Để biết thêm thông tin, hãy xem tài liệu về useActionState.

2.3 React DOM: form Actions

Các Actions cũng được tích hợp với các tính năng mới của React 19 cho react-dom là form. React 19 đã thêm hỗ trợ cho việc truyền các function như action và formAction vào các props của các phần tử form, input, và button để tự động gửi form với các Actions:

Khi một Action của form thành công, React sẽ tự động đặt lại form cho uncontrolled components. Nếu bạn cần reset form một cách thủ công, bạn có thể gọi API mới requestFormReset của React DOM.

<form action={actionFunction}>

2.4 React DOM: New hook: useFormStatus

Trong design systems, việc viết design components mà cần truy cập thông tin về phần tử form mà chúng đang nằm trong, mà không cần truyền props xuống component là phổ biến. Điều này có thể được thực hiện thông qua Context, nhưng để làm cho trường hợp phổ biến dễ dàng hơn, React 19 đã thêm một hook mới là useFormStatus:

import {useFormStatus} from 'react-dom';

function DesignButton() {
  const {pending} = useFormStatus();
  return <button type="submit" disabled={pending} />
}

useFormStatus đọc trạng thái của form cha như thể form là Context provider.

2.5 New hook: useOptimistic

Một common UI phổ biến khác khi thực hiện một sự thay đổi data là hiển thị state cuối cùng một cách optimistically trong khi yêu cầu async đang được thực hiện. Trong React 19, đang thêm một hook mới gọi là useOptimistic để làm việc này dễ dàng hơn:

function ChangeName({currentName, onUpdateName}) {
  const [optimisticName, setOptimisticName] = useOptimistic(currentName);

  const submitAction = async formData => {
    const newName = formData.get("name");
    setOptimisticName(newName);
    const updatedName = await updateName(newName);
    onUpdateName(updatedName);
  };

  return (
    <form action={submitAction}>
      <p>Your name is: {optimisticName}</p>
      <p>
        <label>Change Name:</label>
        <input
          type="text"
          name="name"
          disabled={currentName !== optimisticName}
        />
      </p>
    </form>
  );
}

Hook useOptimistic sẽ ngay lập tức hiển thị optimisticName trong khi yêu cầu cập nhật tên đang được thực hiện. Khi cập nhật hoàn thành hoặc xảy ra lỗi, React sẽ tự động chuyển lại giá trị currentName.

2.6 New API: use

Trong React 19, giới thiệu một API mới để đọc tài nguyên trong render: use. Ví dụ: bạn có thể đọc một promise sử dụng và React sẽ Tạm dừng cho đến khi promise được giải quyết:

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>
  )
}

Bạn cũng có thể đọc context khi sử dụng use, cho phép bạn đọc context có điều kiện, chẳng hạn như sau khi early returns:

import {use} from 'react';
import ThemeContext from './ThemeContext'

function Heading({children}) {
  if (children == null) {
    return null;
  }
  
  // This would not work with useContext
  // because of the early return.
  const theme = use(ThemeContext);
  return (
    <h1 style={{color: theme.color}}>
      {children}
    </h1>
  );
}

API use chỉ có thể được gọi trong render, tương tự như hook. Nhưng không giống như hook, use có thể được gọi có điều kiện. Trong tương lai, React 19 dự định hỗ trợ nhiều cách hơn để tiêu thụ tài nguyên khi kết xuất khi sử dụng.

Còn tiếp... Hẹn gặp lại các bạn ở phần sau!

3. Nguồn tham khảo

https://react.dev/blog/2024/04/25/react-19


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.