參考
use(resource)
在您的元件中呼叫 use
來讀取資源的值,例如 Promise 或 Context。
import { use } from 'react';
function MessageComponent({ messagePromise }) {
const message = use(messagePromise);
const theme = use(ThemeContext);
// ...
與 React Hooks 不同,use
可以在迴圈和條件語句(例如 if
)中呼叫。與 React Hooks 相似,呼叫 use
的函式必須是元件或 Hook。
當使用 Promise 呼叫時,use
API 會與 Suspense
和 錯誤邊界 整合。當傳遞給 use
的 Promise 處於待處理狀態時,呼叫 use
的元件會 _暫停_。如果呼叫 use
的元件被 Suspense 邊界包裝,則會顯示後備內容。一旦 Promise 被解析,Suspense 後備內容將會被使用 use
API 返回的資料渲染的元件取代。如果傳遞給 use
的 Promise 被拒絕,則會顯示最近錯誤邊界的後備內容。
參數
回傳值
use
API 會回傳從資源讀取的值,例如 Promise 的解析值或 context 的值。
注意事項
use
API 必須在元件或 Hook 中呼叫。- 在 伺服器元件 中擷取資料時,建議使用
async
和await
,而不是use
。async
和await
會從呼叫await
的位置繼續渲染,而use
會在資料解析後重新渲染元件。 - 建議在 伺服器元件 中建立 Promise 並將它們傳遞給 客戶端元件,而不是在客戶端元件中建立 Promise。在客戶端元件中建立的 Promise 會在每次渲染時重新建立。從伺服器元件傳遞到客戶端元件的 Promise 在重新渲染期間是穩定的。請參閱此範例。
用法
使用 use
讀取 context
當將 context 傳遞給 use
時,它的工作方式類似於 useContext
。雖然 useContext
必須在元件的最上層呼叫,但 use
可以在條件語句(例如 if
)和迴圈(例如 for
)內呼叫。use
比 useContext
更受歡迎,因為它更靈活。
import { use } from 'react';
function Button() {
const theme = use(ThemeContext);
// ...
use
會針對您傳遞的 context 回傳 context 值。為了確定 context 值,React 會搜尋元件樹,並找到該特定 context **上方最近的 context provider**。
要將 context 傳遞給 Button
,請將它或其父元件之一包裝到對應的 context provider 中。
function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}
function Form() {
// ... renders buttons inside ...
}
provider 和 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
語句內呼叫的,允許您有條件地從 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 作為 prop 從 伺服器元件 傳遞到 客戶端元件,來將資料從伺服器串流到客戶端。
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>
);
}
客戶端元件 接收到 作為 prop 傳遞的 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 解析完成之前,會顯示 fallback。當 Promise 解析完成後,use
API 會讀取值,Message
元件將會取代 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 從伺服器元件傳遞到客戶端元件,並在客戶端元件中使用 use
API 解析。也可以在伺服器元件中使用 await
解析 Promise,並將所需的資料作為 prop 傳遞給客戶端元件。
export default async function App() {
const messageContent = await fetchMessage();
return <Message messageContent={messageContent} />
}
但在 伺服器元件 中使用 await
會阻塞其渲染,直到 await
陳述式完成。將 Promise 從伺服器元件傳遞到客戶端元件可以防止 Promise 阻塞伺服器元件的渲染。
處理 rejected Promise
在某些情況下,傳遞給 use
的 Promise 可能會被拒絕。您可以透過以下兩種方式處理 rejected Promise:
使用錯誤邊界向使用者顯示錯誤
如果您希望在 Promise 被拒絕時向使用者顯示錯誤,您可以使用錯誤邊界。要使用錯誤邊界,請將呼叫 use
API 的元件包裹在錯誤邊界中。如果傳遞給 use
的 Promise 被拒絕,則會顯示錯誤邊界的 fallback。
"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
接受一個參數:一個以錯誤訊息作為參數的函數。傳遞給 catch
的函數 回傳 的任何值都將用作 Promise 的解析值。
疑難排解
「Suspense 異常:這不是一個真正的錯誤!」
您正在 React 組件或 Hook 函式外部調用 use
,或者在 try-catch 區塊中調用 use
。如果您在 try-catch 區塊中調用 use
,請將您的組件包裝在錯誤邊界中,或者調用 Promise 的 catch
方法來捕獲錯誤並使用另一個值來 resolve Promise。參考這些範例。
如果您在 React 組件或 Hook 函式外部調用 use
,請將 use
的調用移至 React 組件或 Hook 函式內。
function MessageComponent({messagePromise}) {
function download() {
// ❌ the function calling `use` is not a Component or Hook
const message = use(messagePromise);
// ...
請在任何組件閉包外部調用 use
,確保調用 use
的函式是組件或 Hook。
function MessageComponent({messagePromise}) {
// ✅ `use` is being called from a component.
const message = use(messagePromise);
// ...