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>;
   }
}

輸出

dowloading data

如何處理被拒絕的 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;

輸出

loading items

使用 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;
}

輸出

welcome my app

缺點

與 useContext 一樣,use(context) 通常會查詢呼叫元件上方最近的 context 提供者。它向上查詢並忽略呼叫 use(context) 的元件中的 context 提供者。

限制

  • 我們應該在元件或 hook 內使用“use”Hook。

  • 當我們在伺服器端時,應始終使用“async”和“await”來很好地獲取資料。

  • 如果我們需要 promises,請在伺服器端建立它們,因為它們保持穩定,但在客戶端,它們可能會發生很大變化。

這一切都是為了使我們的網頁執行得更好、更高效。

reactjs_reference_api.htm
廣告
© . All rights reserved.