リファレンス
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 から読み取られた値を返します。
注意事項
useAPI は、コンポーネントまたはフック内で呼び出す必要があります。- サーバーコンポーネント でデータを取得する場合は、
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);
// ...