ReactJS - use Hook
正如我们在 React 中所知,"hook"是一种特殊函数,它允许我们将状态和其他 React 功能添加到我们的功能组件中。因此,"use"是一个 React Hook,它读取资源的值,例如 Promise 或上下文。与所有其他 React Hook 不同,use 可以在循环和条件表达式(如 if)中调用。与所有其他 React Hook 一样,调用 use 的函数必须是组件或 Hook。
use hook 的基本语法
const data = use(asset);
参数
asset − 它是我们要从中读取值的数据源。因此这可以是 Promise 或上下文。
返回值
此 Hook 将返回从资产读取的值,类似于返回 Promise 或上下文的解析值的方式。
"use"Hook 的用法
import { use } from 'react'; function TheComponent ({ thePromise }) { const msg = use(thePromise); const data = use(DataContext); // ...
带有 Promise 的'use'Hooks(钩子)
因此,通过使用带有'use'Hooks(钩子)的 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>; }
由于 Data 被包裹在 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"Hooks(钩子)的 Promise 可能会被拒绝。因此,我们可以处理这些被拒绝的 Promise,使用错误边界向用户显示错误,或者通过使用 Promise.catch 提供不同的值。
使用错误边界向用户显示错误
假设我们想在 Promise 被拒绝时向用户显示错误,因此我们可以使用错误边界。为此,我们可以在调用"use"Hooks(钩子)的组件周围放置一个错误边界。如果提供给 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"Hooks(钩子)
让我们看另一个"use"Hooks(钩子)的例子。所以我们将在 React − 中使用带有上下文的"use"函数
在这个例子中,我们将有一个用于管理主题的上下文;它可以是浅色或深色。然后我们将有一个名为 MyUseHookApp 的主应用程序组件。它是提供"浅色"主题的顶级组件,并将呈现表单组件。然后我们将创建一个名为 MyForm 的表单组件,该组件将呈现一个面板和三个按钮。之后,面板组件被命名为 MyPanel。它将根据上下文显示具有主题的内容。而 MyButton 组件则根据上下文显示一个具有主题的按钮。
这里所有组件都使用"use"Hooks(钩子)从上下文访问主题,并允许它们根据所选主题设置元素的样式。
示例
import { use, createContext } from 'react'; // 为主题创建上下文 const ThemeContext = createContext(null); // 主应用程序组件。 export default function MyUseHookApp() { return ( // light theme to all components <ThemeContext.Provider value="light"> <MyForm /> </ThemeContext.Provider> ) } // 表单组件 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> ); } // 面板组件用于显示带有主题的内容 function MyPanel({ title, children }) { const theme = use(ThemeContext); // 应用主题 const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } // 按钮组件 function MyButton({ show, children }) { if (show) { const theme = use(ThemeContext); // 将主题应用到组件。 const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); } // If 'show' is false, return nothing. return false; }
输出

缺点
与 useContext 一样,use(context) 会定期查找调用组件上方最近的上下文提供程序。它会查找并忽略调用 use(context) 的组件中的上下文提供程序。
限制
我们应该在组件或Hooks(钩子)中使用"use"Hooks(钩子)。
当我们在服务器上时,我们应该始终使用"async"和"await"来很好地获取数据。
如果我们需要承诺,请在服务器上做出承诺,因为它们保持稳定,但在客户端,它们可能会发生很大变化。
这一切都是为了让我们的网页工作得更好、更高效。