use là một API của React cho phép bạn đọc giá trị của một tài nguyên như Promise hoặc context.

const value = use(resource);

Tham khảo

use(resource)

Gọi use trong component của bạn để đọc giá trị của một tài nguyên như Promise hoặc context.

import { use } from 'react';

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

Không giống như React Hooks, use có thể được gọi bên trong các vòng lặp và các câu lệnh điều kiện như if. Giống như React Hooks, hàm gọi use phải là một Component hoặc Hook.

Khi được gọi với một Promise, API use tích hợp với Suspenseerror boundaries. Component gọi use sẽ tạm dừng trong khi Promise được truyền cho use đang ở trạng thái pending. Nếu component gọi use được bao bọc trong một Suspense boundary, fallback sẽ được hiển thị. Khi Promise được resolve, Suspense fallback sẽ được thay thế bằng các component được render bằng dữ liệu trả về bởi API use. Nếu Promise được truyền cho use bị reject, fallback của Error Boundary gần nhất sẽ được hiển thị.

Xem thêm các ví dụ bên dưới.

Tham số

  • resource: Đây là nguồn dữ liệu mà bạn muốn đọc giá trị. Một resource có thể là một Promise hoặc một context.

Giá trị trả về

API use trả về giá trị được đọc từ resource, chẳng hạn như giá trị đã được resolve của một Promise hoặc context.

Lưu ý

  • API use phải được gọi bên trong một Component hoặc một Hook.
  • Khi tìm nạp dữ liệu trong một Server Component, hãy ưu tiên asyncawait hơn use. asyncawait tiếp tục quá trình render từ điểm mà await được gọi, trong khi use render lại component sau khi dữ liệu được resolve.
  • Ưu tiên tạo Promises trong Server Components và truyền chúng cho Client Components hơn là tạo Promises trong Client Components. Promises được tạo trong Client Components sẽ được tạo lại trên mỗi lần render. Promises được truyền từ một Server Component sang một Client Component sẽ ổn định trên các lần re-render. Xem ví dụ này.

Cách sử dụng

Đọc context với use

Khi một context được truyền cho use, nó hoạt động tương tự như useContext. Trong khi useContext phải được gọi ở cấp cao nhất của component, use có thể được gọi bên trong các điều kiện như if và các vòng lặp như for. use được ưu tiên hơn useContext vì nó linh hoạt hơn.

import { use } from 'react';

function Button() {
const theme = use(ThemeContext);
// ...

use trả về giá trị context cho context mà bạn đã truyền. Để xác định giá trị context, React tìm kiếm trên cây component và tìm context provider gần nhất ở phía trên cho context cụ thể đó.

Để truyền context cho một Button, hãy bọc nó hoặc một trong các component cha của nó vào context provider tương ứng.

function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}

function Form() {
// ... renders buttons inside ...
}

Không quan trọng có bao nhiêu lớp component giữa provider và Button. Khi một Button ở bất kỳ đâu bên trong Form gọi use(ThemeContext), nó sẽ nhận được dark làm giá trị.

Không giống như useContext, use có thể được gọi trong các điều kiện và vòng lặp như if.

function HorizontalRule({ show }) {
if (show) {
const theme = use(ThemeContext);
return <hr className={theme} />;
}
return false;
}

use được gọi từ bên trong một câu lệnh if, cho phép bạn đọc có điều kiện các giá trị từ một Context.

Chú Ý

Giống như useContext, use(context) luôn tìm kiếm context provider gần nhất ở phía trên component gọi nó. Nó tìm kiếm lên trên và không xem xét các context provider trong component mà bạn đang gọi use(context).

import { createContext, use } from 'react';

const ThemeContext = createContext(null);

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button show={true}>Sign up</Button>
      <Button show={false}>Log in</Button>
    </Panel>
  );
}

function Panel({ title, children }) {
  const theme = use(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ show, children }) {
  if (show) {
    const theme = use(ThemeContext);
    const className = 'button-' + theme;
    return (
      <button className={className}>
        {children}
      </button>
    );
  }
  return false
}

Truyền dữ liệu từ server đến client

Dữ liệu có thể được truyền từ server đến client bằng cách truyền một Promise như một prop từ một Server Component đến một Client Component.

import { fetchMessage } from './lib.js';
import { Message } from './message.js';

export default function App() {
const messagePromise = fetchMessage();
return (
<Suspense fallback={<p>waiting for message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}

Client Component sau đó nhận Promise mà nó nhận được như một prop và truyền nó cho API use. Điều này cho phép Client Component đọc giá trị từ Promise ban đầu được tạo bởi Server Component.

// message.js
'use client';

import { use } from 'react';

export function Message({ messagePromise }) {
const messageContent = use(messagePromise);
return <p>Here is the message: {messageContent}</p>;
}

Message được bao bọc trong Suspense, fallback sẽ được hiển thị cho đến khi Promise được resolve. Khi Promise được resolve, giá trị sẽ được đọc bởi API use và component Message sẽ thay thế Suspense fallback.

"use client";

import { use, Suspense } from "react";

function Message({ messagePromise }) {
  const messageContent = use(messagePromise);
  return <p>Here is the message: {messageContent}</p>;
}

export function MessageContainer({ messagePromise }) {
  return (
    <Suspense fallback={<p>⌛Downloading message...</p>}>
      <Message messagePromise={messagePromise} />
    </Suspense>
  );
}

Note

Khi truyền một Promise từ một Server Component đến một Client Component, giá trị đã được resolve của nó phải có thể tuần tự hóa để truyền giữa server và client. Các kiểu dữ liệu như functions không thể tuần tự hóa và không thể là giá trị đã được resolve của một Promise như vậy.

Tìm hiểu sâu

Tôi nên resolve một Promise trong Server Component hay Client Component?

Một Promise có thể được truyền từ một Server Component đến một Client Component và được resolve trong Client Component với API use. Bạn cũng có thể resolve Promise trong một Server Component với await và truyền dữ liệu cần thiết cho Client Component như một prop.

export default async function App() {
const messageContent = await fetchMessage();
return <Message messageContent={messageContent} />
}

Nhưng sử dụng await trong một Server Component sẽ chặn quá trình render của nó cho đến khi câu lệnh await kết thúc. Truyền một Promise từ một Server Component đến một Client Component ngăn Promise chặn quá trình render của Server Component.

Xử lý các Promise bị reject

Trong một số trường hợp, một Promise được truyền cho use có thể bị reject. Bạn có thể xử lý các Promise bị reject bằng một trong hai cách:

  1. Hiển thị lỗi cho người dùng bằng error boundary.
  2. Cung cấp một giá trị thay thế với Promise.catch

Chú Ý

Hiển thị lỗi cho người dùng bằng error boundary

Nếu bạn muốn hiển thị lỗi cho người dùng khi một Promise bị reject, bạn có thể sử dụng một error boundary. Để sử dụng một error boundary, hãy bọc component nơi bạn đang gọi API use trong một error boundary. Nếu Promise được truyền cho use bị reject, fallback cho error boundary sẽ được hiển thị.

"use client";

import { use, Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";

export function MessageContainer({ messagePromise }) {
  return (
    <ErrorBoundary fallback={<p>⚠️Something went wrong</p>}>
      <Suspense fallback={<p>⌛Downloading message...</p>}>
        <Message messagePromise={messagePromise} />
      </Suspense>
    </ErrorBoundary>
  );
}

function Message({ messagePromise }) {
  const content = use(messagePromise);
  return <p>Here is the message: {content}</p>;
}

Cung cấp một giá trị thay thế với Promise.catch

Nếu bạn muốn cung cấp một giá trị thay thế khi Promise được truyền cho use bị reject, bạn có thể sử dụng phương thức catch của Promise.

import { Message } from './message.js';

export default function App() {
const messagePromise = new Promise((resolve, reject) => {
reject();
}).catch(() => {
return "no new message found.";
});

return (
<Suspense fallback={<p>waiting for message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}

Để sử dụng phương thức catch của Promise, hãy gọi catch trên đối tượng Promise. catch nhận một đối số duy nhất: một hàm nhận một thông báo lỗi làm đối số. Bất cứ điều gì được trả về bởi hàm được truyền cho catch sẽ được sử dụng làm giá trị đã được resolve của Promise.


Khắc phục sự cố

“Suspense Exception: This is not a real error!”

Bạn đang gọi use bên ngoài một React Component hoặc hàm Hook, hoặc gọi use trong một khối try-catch. Nếu bạn đang gọi use bên trong một khối try-catch, hãy bọc component của bạn trong một error boundary, hoặc gọi catch của Promise để bắt lỗi và resolve Promise với một giá trị khác. Xem các ví dụ này.

Nếu bạn đang gọi use bên ngoài một React Component hoặc hàm Hook, hãy di chuyển lệnh gọi use đến một React Component hoặc hàm Hook.

function MessageComponent({messagePromise}) {
function download() {
// ❌ hàm gọi `use` không phải là một Component hoặc Hook
const message = use(messagePromise);
// ...

Thay vào đó, hãy gọi use bên ngoài bất kỳ closure component nào, nơi hàm gọi use là một Component hoặc Hook.

function MessageComponent({messagePromise}) {
// ✅ `use` đang được gọi từ một component.
const message = use(messagePromise);
// ...