參考
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 的值。
注意事項
useAPI 必須在元件或 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);
// ...