use - This feature is available in the latest Canary

Canary

use API 目前仅在 React 的 Canary 和实验渠道中可用。了解有关 React 的发布渠道在这里 的更多信息。

¥The use API is currently only available in React’s Canary and experimental channels. Learn more about React’s release channels here.

use 是一个 React API,可让你读取资源的值,例如 Promise上下文

¥use is a React API that lets you read the value of a resource like a Promise or context.

const value = use(resource);

参考

¥Reference

use(resource)

在组件中调用 use 来读取 Promise上下文 等资源的值。

¥Call use in your component to read the value of a resource like a Promise or context.

import { use } from 'react';

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

与 React 钩子不同,use 可以在循环和条件语句中调用,如 if。与 React 钩子一样,调用 use 的函数必须是组件或 Hook。

¥Unlike React Hooks, use can be called within loops and conditional statements like if. Like React Hooks, the function that calls use must be a Component or Hook.

当使用 Promise 调用时,use API 与 Suspense误差边界 集成。当传递给 use 的 Promise 处于挂起状态时,调用 use 的组件会挂起。如果调用 use 的组件包含在 Suspense 边界中,则将显示回退。一旦 Promise 得到解决,Suspense 回退将被使用 use API 返回的数据由渲染的组件替换。如果传递给 use 的 Promise 被拒绝,则会显示最近的错误边界的回退。

¥When called with a Promise, the use API integrates with Suspense and error boundaries. The component calling use suspends while the Promise passed to use is pending. If the component that calls use is wrapped in a Suspense boundary, the fallback will be displayed. Once the Promise is resolved, the Suspense fallback is replaced by the rendered components using the data returned by the use API. If the Promise passed to use is rejected, the fallback of the nearest Error Boundary will be displayed.

请参阅下面的更多示例。

¥See more examples below.

参数

¥Parameters

  • resource:这是你要从中读取值的数据源。资源可以是 Promise上下文

    ¥resource: this is the source of the data you want to read a value from. A resource can be a Promise or a context.

返回

¥Returns

use API 返回从资源读取的值,如 Promise上下文 的解析值。

¥The use API returns the value that was read from the resource like the resolved value of a Promise or context.

注意事项

¥Caveats

  • use API 必须在组件或钩子内调用。

    ¥The use API must be called inside a Component or a Hook.

  • 服务器组件 中获取数据时,优先选择 asyncawait 而不是 useasyncawait 从调用 await 的位置开始渲染,而 use 在解析数据后重新渲染组件。

    ¥When fetching data in a Server Component, prefer async and await over use. async and await pick up rendering from the point where await was invoked, whereas use re-renders the component after the data is resolved.

  • 与在客户端组件中创建 Promise 相比,更喜欢在 服务器组件 中创建 Promise 并将它们传递给 客户端组件。在客户端组件中创建的 Promise 会在每次渲染时重新创建。从服务器组件传递到客户端组件的 Promise 在重新渲染过程中是稳定的。看这个例子

    ¥Prefer creating Promises in Server Components and passing them to Client Components over creating Promises in Client Components. Promises created in Client Components are recreated on every render. Promises passed from a Server Component to a Client Component are stable across re-renders. See this example.


用法

¥Usage

use 一起阅读上下文

¥Reading context with use

上下文 传递给 use 时,其工作方式与 useContext 类似。虽然 useContext 必须在组件的顶层调用,但 use 可以在条件语句(如 if)和循环(如 for)内部调用。use 优于 useContext,因为它更灵活。

¥When a context is passed to use, it works similarly to useContext. While useContext must be called at the top level of your component, use can be called inside conditionals like if and loops like for. use is preferred over useContext because it is more flexible.

import { use } from 'react';

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

use 为你传递的 上下文 返回的 上下文值。为了确定上下文值,React 搜索组件树并找到上面与该特定上下文最接近的上下文提供者。

¥use returns the context value for the context you passed. To determine the context value, React searches the component tree and finds the closest context provider above for that particular context.

要将上下文传递给 Button,请将其或其父组件之一封装到相应的上下文提供程序中。

¥To pass context to a Button, wrap it or one of its parent components into the corresponding context provider.

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

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

提供器和 Button 之间有多少层组件并不重要。当 Form 内部任何位置的 Button 调用 use(ThemeContext) 时,它将接收 "dark" 作为值。

¥It doesn’t matter how many layers of components there are between the provider and the Button. When a Button anywhere inside of Form calls use(ThemeContext), it will receive "dark" as the value.

useContext 不同,use 可以在条件和循环中调用,如 if

¥Unlike useContext, use can be called in conditionals and loops like if.

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

useif 语句内部调用,允许你有条件地从 Context 读取值。

¥use is called from inside a if statement, allowing you to conditionally read values from a Context.

易犯错误

useContext 一样,use(context) 始终在调用它的组件上方寻找最接近的上下文提供程序。它向上搜索,并且不考虑你调用 use(context) 的组件中的上下文提供程序。

¥Like useContext, use(context) always looks for the closest context provider above the component that calls it. It searches upwards and does not consider context providers in the component from which you’re calling 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
}

将数据从服务器流式传输到客户端

¥Streaming data from the server to the client

通过将 Promise 作为属性从 Server Component 传递到 Client Component,可以将数据从服务器流式传输到客户端。

¥Data can be streamed from the server to the client by passing a Promise as a prop from a Server Component to a 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>
);
}

然后,客户端组件它作为属性收到的 Promise 传递给 use API。这允许客户端组件从最初由服务器组件创建的Promise读取值。

¥The Client Component then takes the Promise it received as a prop and passes it to the use API. This allows the Client Component to read the value from the Promise that was initially created by the 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 封装在 Suspense 中,因此将显示回退,直到 Promise 得到解析。当 Promise 被解析时,该值将由 use API 读取,并且 Message 组件将替换 Suspense 回退。

¥Because Message is wrapped in Suspense, the fallback will be displayed until the Promise is resolved. When the Promise is resolved, the value will be read by the use API and the Message component will replace the 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>
  );
}

注意

将 Promise 从服务器组件传递到客户端组件时,其解析值必须可序列化才能在服务器和客户端之间传递。像函数这样的数据类型是不可序列化的,并且不能是此类 Promise 的解析值。

¥When passing a Promise from a Server Component to a Client Component, its resolved value must be serializable to pass between server and client. Data types like functions aren’t serializable and cannot be the resolved value of such a Promise.

深入研究

我应该在服务器或客户端组件中解析 Promise 吗?

¥Should I resolve a Promise in a Server or Client Component?

Promise 可以从服务器组件传递到客户端组件,并使用 use API 在客户端组件中解析。你还可以使用 await 解析服务器组件中的 Promise,并将所需的数据作为属性传递给客户端组件。

¥A Promise can be passed from a Server Component to a Client Component and resolved in the Client Component with the use API. You can also resolve the Promise in a Server Component with await and pass the required data to the Client Component as a prop.

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

但是在 服务器组件 中使用 await 将阻止其渲染,直到 await 语句完成。将 Promise 从服务器组件传递到客户端组件可以防止 Promise 阻止服务器组件的渲染。

¥But using await in a Server Component will block its rendering until the await statement is finished. Passing a Promise from a Server Component to a Client Component prevents the Promise from blocking the rendering of the Server Component.

处理被拒绝的 Promise

¥Dealing with rejected Promises

在某些情况下,传递给 use 的 Promise 可能会被拒绝。你可以通过以下任一方式处理被拒绝的 Promise:

¥In some cases a Promise passed to use could be rejected. You can handle rejected Promises by either:

  1. 向用户显示带有错误边界的错误。

    ¥Displaying an error to users with an error boundary.

  2. 使用 Promise.catch 提供替代值

    ¥Providing an alternative value with Promise.catch

易犯错误

无法在 try-catch 块中调用 use。而不是 try-catch 块 将你的组件封装在错误边界中提供与 Promise 的 .catch 方法一起使用的替代值

¥use cannot be called in a try-catch block. Instead of a try-catch block wrap your component in an Error Boundary, or provide an alternative value to use with the Promise’s .catch method.

向用户显示带有错误边界的错误

¥Displaying an error to users with an error boundary

如果你想在 Promise 被拒绝时向用户显示错误,你可以使用 误差边界。要使用错误边界,请将调用 use API 的组件封装在错误边界中。如果传递给 use 的 Promise 被拒绝,则会显示错误边界的回退。

¥If you’d like to display an error to your users when a Promise is rejected, you can use an error boundary. To use an error boundary, wrap the component where you are calling the use API in an error boundary. If the Promise passed to use is rejected the fallback for the error boundary will be displayed.

"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>;
}

使用 Promise.catch 提供替代值

¥Providing an alternative value with Promise.catch

如果你想在传递给 use 的 Promise 被拒绝时提供替代值,你可以使用 Promise 的 catch 方法。

¥If you’d like to provide an alternative value when the Promise passed to use is rejected you can use the Promise’s catch method.

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

要使用 Promise 的 catch 方法,请在 Promise 对象上调用 catchcatch 采用单个参数:将错误消息作为参数的函数。传递给 catch 的函数返回的任何 都将用作 Promise 的解析值。

¥To use the Promise’s catch method, call catch on the Promise object. catch takes a single argument: a function that takes an error message as an argument. Whatever is returned by the function passed to catch will be used as the resolved value of the Promise.


故障排除

¥Troubleshooting

“Suspense 例外:这不是真正的错误!”

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

你要么在 React 组件或钩子函数之外调用 use,要么在 try–catch 块中调用 use。如果你在 try-catch 块内调用 use,请将组件封装在错误边界中,或调用 Promise 的 catch 来捕获错误并使用另一个值解析 Promise。请参阅这些示例

¥You are either calling use outside of a React Component or Hook function, or calling use in a try–catch block. If you are calling use inside a try–catch block, wrap your component in an error boundary, or call the Promise’s catch to catch the error and resolve the Promise with another value. See these examples.

如果你在 React 组件或钩子函数之外调用 use,请将 use 调用移至 React 组件或钩子函数。

¥If you are calling use outside a React Component or Hook function, move the use call to a React Component or Hook function.

function MessageComponent({messagePromise}) {
function download() {
// ❌ the function calling `use` is not a Component or Hook
const message = use(messagePromise);
// ...

相反,在任何组件闭包之外调用 use,其中调用 use 的函数是组件或 Hook。

¥Instead, call use outside any component closures, where the function that calls use is a Component or Hook.

function MessageComponent({messagePromise}) {
// ✅ `use` is being called from a component.
const message = use(messagePromise);
// ...

React 中文网 - 粤ICP备13048890号