use は、Promiseコンテキスト などのリソースの値を読み取るためのReact APIです。

const value = use(resource);

リファレンス

use(resource)

コンポーネント内でuse を呼び出して、Promiseコンテキスト などのリソースの値を読み取ります。

import { use } from 'react';

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

Reactフックとは異なり、use は、if などのループや条件文内で呼び出すことができます。Reactフックと同様に、use を呼び出す関数は、コンポーネントまたはフックでなければなりません。

Promise を使用して呼び出された場合、use API は Suspenseエラーバウンダリ と統合されます。use を呼び出すコンポーネントは、use に渡されたPromiseが保留されている間、 *中断* します。 use を呼び出すコンポーネントがSuspenseバウンダリでラップされている場合、フォールバックが表示されます。Promiseが解決されると、Suspenseフォールバックは、use APIによって返されたデータを使用するレンダリングされたコンポーネントに置き換えられます。use に渡されたPromiseが拒否された場合、最も近いエラーバウンダリのフォールバックが表示されます。

以下の例を参照してください。

パラメーター

戻り値

use API は、Promise または コンテキスト の解決済み値のように、resource から読み取られた値を返します。

注意事項

  • use API は、コンポーネントまたはフック内で呼び出す必要があります。
  • サーバーコンポーネント でデータを取得する場合は、use よりも asyncawait を優先してください。asyncawaitawait が呼び出された時点からレンダリングを再開しますが、use はデータが解決された後にコンポーネントを再レンダリングします。
  • サーバーコンポーネント で Promise を作成し、それを クライアントコンポーネント に渡すことを、クライアントコンポーネントで Promise を作成することよりも優先してください。クライアントコンポーネントで作成された Promise は、レンダリングごとに再作成されます。サーバーコンポーネントからクライアントコンポーネントに渡された Promise は、再レンダリング間で安定しています。この例を参照してください

使用方法

use を使用したコンテキストの読み取り

コンテキストuse に渡されると、useContext と同様に動作します。useContext はコンポーネントの最上位レベルで呼び出す必要がありますが、useifのような条件式やforのようなループ内で呼び出すことができます。use はより柔軟であるため、useContext よりも優先されます。

import { use } from 'react';

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

use は、渡された コンテキストコンテキスト値 を返します。コンテキスト値を決定するために、React はコンポーネントツリーを検索し、その特定のコンテキストに対する 最も近い上位のコンテキストプロバイダー を探します。

コンテキストをButton に渡すには、Button またはその親コンポーネントのいずれかを対応するコンテキストプロバイダーでラップします。

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

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

プロバイダーとButton の間にコンポーネントがいくつあっても問題ありません。Form 内の任意の場所にあるButtonuse(ThemeContext)を呼び出すと、"dark"という値を受け取ります。

useContext とは異なり、useif のような条件式やループ内で呼び出すことができます。

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

useif 文の中から呼び出せるため、コンテキストから値を条件付きで読み取ることができます。

落とし穴

useContext と同様に、use(context) は常に、それを呼び出しているコンポーネントの上位にある最も近いコンテキストプロバイダーを探します。上方向に検索し、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
}

サーバーからクライアントへのデータストリーミング

データは、サーバーコンポーネントからクライアントコンポーネントへプロップとしてPromiseを渡すことで、サーバーからクライアントにストリーミングできます。

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

クライアントコンポーネントは、次にプロップとして受け取ったPromiseuse APIに渡します。これにより、クライアントコンポーネントは、サーバーコンポーネントによって最初に作成されたPromiseの値を読み取ることができます。

// message.js
'use client';

import { use } from 'react';

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

MessageSuspenseでラップされているため、Promiseが解決されるまでフォールバックが表示されます。Promiseが解決されると、use APIによって値が読み取られ、MessageコンポーネントがSuspenseのフォールバックに置き換わります。

"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の解決済み値にすることはできません。

詳細

Promiseはサーバーコンポーネントで解決すべきか、クライアントコンポーネントで解決すべきか?

Promiseはサーバーコンポーネントからクライアントコンポーネントに渡され、use APIを使用してクライアントコンポーネントで解決できます。awaitを使用してサーバーコンポーネントでPromiseを解決し、必要なデータをプロップとしてクライアントコンポーネントに渡すこともできます。

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

しかし、サーバーコンポーネントawaitを使用すると、await文が終了するまでレンダリングがブロックされます。サーバーコンポーネントからクライアントコンポーネントにPromiseを渡すことで、Promiseがサーバーコンポーネントのレンダリングをブロックするのを防ぎます。

拒否されたPromiseの処理

useに渡されたPromiseが拒否される場合もあります。拒否されたPromiseは、次のいずれかの方法で処理できます。

  1. エラー境界を使用して、ユーザーにエラーを表示する。
  2. Promise.catchを使用して代替値を提供する。

落とし穴

useはtry-catchブロック内で呼び出すことができません。try-catchブロックの代わりにコンポーネントをエラー境界でラップするかPromiseの.catchメソッドを使用して代替値を提供します

エラー境界を使用してユーザーにエラーを表示する

Promiseが拒否されたときにユーザーにエラーを表示したい場合は、エラー境界を使用できます。エラー境界を使用するには、use APIを呼び出しているコンポーネントをエラー境界でラップします。useに渡されたPromiseが拒否されると、エラー境界のフォールバックが表示されます。

"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を使用して代替値を提供する

useに渡されたPromiseが拒否されたときに代替値を提供したい場合は、Promiseのcatchメソッドを使用できます。

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オブジェクトに対してcatchを呼び出します。catchは、引数としてエラーメッセージを受け取る関数を1つだけ引数として受け取ります。返されたcatchに渡された関数によって返される値は、Promiseの解決済み値として使用されます。


トラブルシューティング

「Suspense Exception: This is not a real error!」

Reactコンポーネントまたはフック関数の外部でuseを呼び出しているか、try-catchブロック内でuseを呼び出しているかのいずれかです。try-catchブロック内でuseを呼び出している場合は、コンポーネントをエラーバウンダリでラップするか、Promiseのcatchを呼び出してエラーをキャッチし、別の値でPromiseを解決します。これらの例を参照してください

Reactコンポーネントまたはフック関数の外部でuseを呼び出している場合は、use呼び出しをReactコンポーネントまたはフック関数に移動してください。

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

代わりに、useを呼び出す関数がコンポーネントまたはフックである場所、つまり、コンポーネントクロージャの外部でuseを呼び出してください。

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