- 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,请在服务器端创建它们,因为它们保持稳定,但在客户端,它们可能会发生很大变化。
这一切都是为了使我们的网页运行得更好、更高效。