- ReactJS 教程
- ReactJS - 首頁
- ReactJS - 簡介
- ReactJS - 路線圖
- ReactJS - 安裝
- ReactJS - 特性
- ReactJS - 優點與缺點
- ReactJS - 架構
- ReactJS - 建立 React 應用
- ReactJS - JSX
- ReactJS - 元件
- ReactJS - 巢狀元件
- ReactJS - 使用新建立的元件
- ReactJS - 元件集合
- ReactJS - 樣式
- ReactJS - 屬性 (props)
- ReactJS - 使用屬性建立元件
- ReactJS - props 驗證
- ReactJS - 建構函式
- ReactJS - 元件生命週期
- ReactJS - 事件管理
- ReactJS - 建立一個事件感知元件
- ReactJS - 在 Expense Manager 應用中引入事件
- ReactJS - 狀態管理
- ReactJS - 狀態管理 API
- ReactJS - 無狀態元件
- ReactJS - 使用 React Hooks 進行狀態管理
- ReactJS - 使用 React Hooks 進行元件生命週期管理
- ReactJS - 佈局元件
- ReactJS - 分頁
- ReactJS - Material UI
- ReactJS - Http 客戶端程式設計
- ReactJS - 表單程式設計
- ReactJS - 受控元件
- ReactJS - 非受控元件
- ReactJS - Formik
- ReactJS - 條件渲染
- ReactJS - 列表
- ReactJS - Keys
- ReactJS - 路由
- ReactJS - Redux
- ReactJS - 動畫
- ReactJS - Bootstrap
- ReactJS - Map
- ReactJS - 表格
- ReactJS - 使用 Flux 管理狀態
- ReactJS - 測試
- ReactJS - CLI 命令
- ReactJS - 構建和部署
- ReactJS - 示例
- Hooks
- ReactJS - Hook 簡介
- ReactJS - 使用 useState
- ReactJS - 使用 useEffect
- ReactJS - 使用 useContext
- ReactJS - 使用 useRef
- ReactJS - 使用 useReducer
- ReactJS - 使用 useCallback
- ReactJS - 使用 useMemo
- ReactJS - 自定義 Hook
- ReactJS 高階
- ReactJS - 可訪問性
- ReactJS - 程式碼分割
- ReactJS - Context
- ReactJS - 錯誤邊界
- ReactJS - 轉發 Refs
- ReactJS - Fragments
- ReactJS - 高階元件
- ReactJS - 與其他庫整合
- ReactJS - 效能最佳化
- ReactJS - Profiler API
- ReactJS - Portals
- ReactJS - 無 ES6 ECMAScript 的 React
- ReactJS - 無 JSX 的 React
- ReactJS - 調和
- ReactJS - Refs 和 DOM
- ReactJS - Render Props
- ReactJS - 靜態型別檢查
- ReactJS - Strict Mode
- ReactJS - Web Components
- 其他概念
- ReactJS - 日期選擇器
- ReactJS - Helmet
- ReactJS - 內聯樣式
- ReactJS - PropTypes
- ReactJS - BrowserRouter
- ReactJS - DOM
- ReactJS - 走馬燈
- ReactJS - 圖示
- ReactJS - 表單元件
- ReactJS - 參考 API
- ReactJS 有用資源
- ReactJS - 快速指南
- ReactJS - 有用資源
- ReactJS - 討論
ReactJS - 使用 Hook
眾所周知,在 React 中,“hook”是一個特殊的函式,它允許我們將狀態和其他 React 功能新增到我們的函式式元件中。“use”是一個 React Hook,它讀取資源的值,例如 Promise 或 context。與所有其他 React Hook 不同,“use”可以在迴圈和條件表示式(如 if)中呼叫。呼叫“use”的函式,與所有其他 React Hook 一樣,必須是一個元件或 Hook。
“use” Hook 的基本語法
const data = use(asset);
引數
asset − 它是我們要從中讀取值的資料來源。因此,它可以是 Promise 或 context。
返回值
此 Hook 將返回從 asset 讀取的值,類似於返回 Promise 或 context 的已解析值。
‘use’ Hook 的用法
import { use } from 'react';
function TheComponent ({ thePromise }) {
const msg = use(thePromise);
const data = use(DataContext);
// ...
帶有 Promise 的 ‘use’ hook
透過使用帶有 ‘use’ hook 的 promise,我們可以將資料從伺服器流式傳輸到客戶端。透過從伺服器元件向客戶端元件提供 Promise 作為 prop,可以將資料從伺服器傳送到客戶端。
import { Data } from './data.js';
export default function App() {
const dataPromise = fetchData();
return (
<Suspense fallback={<p>waiting for the data...</p>}>
<Message dataPromise={dataPromise} />
</Suspense>
);
}
然後,客戶端元件將作為 prop 提供給它的 Promise 傳遞給 use Hook。這使客戶端元件能夠讀取伺服器元件首先生成的 Promise 中的值。
data.js
'use client';
import { use } from 'react';
export function Data({ dataPromise }) {
const dataContent = use(dataPromise);
return <h4>Here is the data: {dataContent}</h4>;
}
由於資料被包裝在 Suspense 中,因此在 Promise 解析之前將顯示回退內容。當 Promise 解析後,Hook 將讀取該值,並且 Data 元件將取代 Suspense 回退內容。
完整程式碼
Data.js
"use client";
import { use, Suspense } from "react";
function Data({ dataPromise }) {
const dataContent = use(dataPromise);
return <h4>Yup!!! Here is the Data: {dataContent}</h4>;
}
export function DataContainer({ dataPromise }) {
return (
<Suspense fallback={<p>⌛ Downloading Data...</p>}>
<Data dataPromise={dataPromise} />
</Suspense>
);
}
App.js
import { useState } from "react";
import { DataContainer } from "./data.js";
function fetchData() {
return new Promise((resolve) => setTimeout(resolve, 2000, "😃"));
}
export default function App() {
const [dataPromise, setDataPromise] = useState(null);
const [show, setShow] = useState(false);
function download() {
setDataPromise(fetchData());
setShow(true);
}
if (show) {
return <DataContainer dataPromise={dataPromise} />;
} else {
return <button onClick={download}>Download Your Data</button>;
}
}
輸出
如何處理被拒絕的 Promise
有時傳遞給 ‘use’ hook 的 Promise 可能會被拒絕。因此,我們可以透過使用錯誤邊界向用戶顯示錯誤或透過使用 Promise.catch 提供不同的值來處理這些被拒絕的 Promise。
使用錯誤邊界向用戶顯示錯誤
假設我們希望在 Promise 被拒絕時向用戶顯示錯誤,那麼我們可以使用錯誤邊界。為此,我們可以將錯誤邊界放在我們呼叫 ‘use’ Hook 的元件周圍。如果提供給 use 的 Promise 被拒絕,則將顯示錯誤邊界的回退內容。
示例
ItemListContainer.js
import { use, Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";
export function ItemListContainer({ itemListPromise }) {
return (
<ErrorBoundary fallback={<p>⚠ Something went wrong</p>}>
<Suspense fallback={<p>⌛ Loading items...</p>}>
<ItemList itemListPromise={itemListPromise} />
</Suspense>
</ErrorBoundary>
);
}
function ItemList({ itemListPromise }) {
const items = use(itemListPromise);
return (
<div>
<h2>Item List:</h2>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
App.js
import { useState } from "react";
import { ItemListContainer } from "./ItemListContainer";
function fetchItems() {
return new Promise((resolve) =>
setTimeout(() => resolve(["Item 1", "Item 2", "Item 3"]), 1000)
);
}
function App() {
const [itemListPromise, setItemListPromise] = useState(null);
const [show, setShow] = useState(false);
function loadItems() {
setItemListPromise(fetchItems());
setShow(true);
}
if (show) {
return <ItemListContainer itemListPromise={itemListPromise} />;
} else {
return <button onClick={loadItems}>Load Items</button>;
}
}
export default App;
輸出
使用 Promise.catch 提供替代值
如果提供的 Promise 被拒絕,我們可以使用 catch 方法提供替代值。
import { Data } from './data.js';
export default function App() {
const dataPromise = new Promise((resolve, reject) => {
reject();
}).catch(() => {
return "No data found.";
});
return (
<Suspense fallback={<p>waiting for the data...</p>}>
<Data dataPromise={dataPromise} />
</Suspense>
);
}
帶有 Context 的 ‘use’ hook
讓我們看看 ‘use’ hook 的另一個示例。我們將使用 React 中的 ‘use’ 函式和 context −
在這個例子中,我們將有一個用於管理主題的 context;它可以是淺色或深色。然後我們將有一個名為 MyUseHookApp 的主應用程式元件。它是提供“淺色”主題並渲染表單元件的頂級元件。然後我們將建立一個名為 MyForm 的表單元件,它是一個將渲染面板和三個按鈕的元件。之後,面板元件名為 MyPanel。它將根據 context 顯示具有主題的內容。MyButton 元件將根據 context 顯示具有主題的按鈕。
這裡所有元件都使用“use”hook 從 context 訪問主題,並允許它們根據所選主題設定元素樣式。
示例
import { use, createContext } from 'react';
// Create a context for theme
const ThemeContext = createContext(null);
// Main App component.
export default function MyUseHookApp() {
return (
// light theme to all components
<ThemeContext.Provider value="light">
<MyForm />
</ThemeContext.Provider>
)
}
// Form component
function MyForm() {
return (
<MyPanel title="Welcome To My App">
<MyButton show={true}>Join Here</MyButton>
<MyButton show={true}>Begin</MyButton>
<MyButton show={false}>Settings</MyButton>
</MyPanel>
);
}
// Panel component to display content with a theme
function MyPanel({ title, children }) {
const theme = use(ThemeContext);
// Apply the theme
const className = 'panel-' + theme;
return (
<section className={className}>
<h1>{title}</h1>
{children}
</section>
)
}
// Button component
function MyButton({ show, children }) {
if (show) {
const theme = use(ThemeContext);
// Apply the theme to the component.
const className = 'button-' + theme;
return (
<button className={className}>
{children}
</button>
);
}
// If 'show' is false, return nothing.
return false;
}
輸出
缺點
與 useContext 一樣,use(context) 通常會查詢呼叫元件上方最近的 context 提供者。它向上查詢並忽略呼叫 use(context) 的元件中的 context 提供者。
限制
我們應該在元件或 hook 內使用“use”Hook。
當我們在伺服器端時,應始終使用“async”和“await”來很好地獲取資料。
如果我們需要 promises,請在伺服器端建立它們,因為它們保持穩定,但在客戶端,它們可能會發生很大變化。
這一切都是為了使我們的網頁執行得更好、更高效。