リファレンス
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
よりもasync
とawait
を優先してください。async
とawait
はawait
が呼び出された時点からレンダリングを再開しますが、use
はデータが解決された後にコンポーネントを再レンダリングします。 - サーバーコンポーネント で Promise を作成し、それを クライアントコンポーネント に渡すことを、クライアントコンポーネントで Promise を作成することよりも優先してください。クライアントコンポーネントで作成された Promise は、レンダリングごとに再作成されます。サーバーコンポーネントからクライアントコンポーネントに渡された Promise は、再レンダリング間で安定しています。この例を参照してください。
使用方法
use
を使用したコンテキストの読み取り
コンテキスト が use
に渡されると、useContext
と同様に動作します。useContext
はコンポーネントの最上位レベルで呼び出す必要がありますが、use
はif
のような条件式や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
内の任意の場所にあるButton
がuse(ThemeContext)
を呼び出すと、"dark"
という値を受け取ります。
useContext
とは異なり、use
は if
のような条件式やループ内で呼び出すことができます。
function HorizontalRule({ show }) {
if (show) {
const theme = use(ThemeContext);
return <hr className={theme} />;
}
return false;
}
use
は if
文の中から呼び出せるため、コンテキストから値を条件付きで読み取ることができます。
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>
);
}
クライアントコンポーネントは、次にプロップとして受け取ったPromiseをuse
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>;
}
Message
がSuspense
でラップされているため、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はサーバーコンポーネントからクライアントコンポーネントに渡され、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は、次のいずれかの方法で処理できます。
エラー境界を使用してユーザーにエラーを表示する
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);
// ...