React強大且靈活hooks庫——ahooks入門實踐之場景類(scene)hook詳解

什么是 ahooks?

ahooks 是一個 React Hooks 庫,提供了大量實用的自定義 hooks,幫助開發者更高效地構建 React 應用。其中場景類 hooks 是 ahooks 的一個重要分類,專門針對特定業務場景提供解決方案。

安裝 ahooks

npm install ahooks

場景類 hook 詳解

useAntdTable – Antd 表格集成

useAntdTable用于處理表格與表單的聯動場景。

import React from "react";
import { useAntdTable } from "ahooks";
import { Form, Input, Button, Table } from "antd";const UserTable = () => {const [form] = Form.useForm();const { tableProps, search } = useAntdTable(async (params, form) => {const { current, pageSize } = params;const response = await fetch("/api/users", {method: "POST",body: JSON.stringify({page: current,size: pageSize,...form,}),});const data = await response.json();return {list: data.list,total: data.total,};},{form,defaultPageSize: 10,});return (<div className="container m-4"><Form form={form} layout="inline" className="mb-2"><Form.Item name="name" label="姓名"><Input placeholder="請輸入姓名" /></Form.Item><Form.Item name="email" label="郵箱"><Input placeholder="請輸入郵箱" /></Form.Item><Form.Item><Button type="primary" onClick={search.submit}>搜索</Button><Button onClick={search.reset} style={{ marginLeft: 8 }}>重置</Button></Form.Item></Form><Table{...tableProps}columns={[{ title: "姓名", dataIndex: "name" },{ title: "郵箱", dataIndex: "email" },{ title: "創建時間", dataIndex: "createTime" },]}/></div>);
};

useFusionTable – Fusion 表格集成

useFusionTable用于處理表格與表單的聯動場景。

import React from "react";
import { useFusionTable } from "ahooks";
import { Table, Button, Input } from "@alifd/next";const UserTable = () => {const { tableProps, search, loading } = useFusionTable(async (params) => {const { current, pageSize, ...rest } = params;const response = await fetch("/api/users", {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({page: current,size: pageSize,...rest,}),});const data = await response.json();return {list: data.list,total: data.total,};},{defaultPageSize: 10,defaultParams: [{ current: 1, pageSize: 10 }],});return (<div><div style={{ marginBottom: 16 }}><Inputplaceholder="搜索用戶名"onChange={(value) => search.setFieldValue("name", value)}style={{ width: 200, marginRight: 8 }}/><Button type="primary" onClick={search.submit}>搜索</Button><Button onClick={search.reset} style={{ marginLeft: 8 }}>重置</Button></div><Table {...tableProps} loading={loading}><Table.Column title="姓名" dataIndex="name" /><Table.Column title="郵箱" dataIndex="email" /><Table.Column title="創建時間" dataIndex="createTime" /></Table></div>);
};

useInfiniteScroll – 無限滾動

import React from "react";
import { useInfiniteScroll } from "ahooks";const InfiniteList = () => {const { data, loading, noMore } = useInfiniteScroll(async (d) => {const { list = [], total = 0 } = await fetchData(d?.list?.length || 0);return {list: [...(d?.list || []), ...list],total,};},{target: document,isNoMore: (d) => d?.list?.length >= d?.total,threshold: 100,});return (<div style={{ height: "100vh", overflow: "auto" }}>{data?.list?.map((item, index) => (<divkey={`${item.id}-${index}`}style={{padding: "12px",borderBottom: "1px solid #eee",backgroundColor: index % 2 === 0 ? "#f9f9f9" : "white",}}><h3>{item.title}</h3><p>{item.description}</p></div>))}{loading && (<div style={{ textAlign: "center", padding: "20px" }}>加載中...</div>)}{noMore && (<div style={{ textAlign: "center", padding: "20px", color: "#999" }}>沒有更多數據了</div>)}</div>);
};// 模擬數據獲取函數
const fetchData = async (offset = 0) => {// 模擬API調用await new Promise((resolve) => setTimeout(resolve, 1000));const pageSize = 10;const mockData = Array.from({ length: pageSize }, (_, i) => ({id: offset + i,title: `項目 ${offset + i + 1}`,description: `這是第 ${offset + i + 1} 個項目的描述`,}));return {list: mockData,total: 50, // 總共50條數據};
};export default InfiniteList;

usePagination – 分頁管理

import React from "react";
import { usePagination } from "ahooks";
import { Button, Input } from "antd";const PaginationExample = () => {const { data, loading, pagination, run } = usePagination(async ({ current, pageSize }) => {const response = await fetch(`/api/users?page=${current}&size=${pageSize}`);return response.json();},{defaultPageSize: 5,defaultCurrent: 1,});const [searchValue, setSearchValue] = React.useState("");const handleSearch = () => {run({ current: 1, pageSize: pagination.pageSize, search: searchValue });};return (<div><div style={{ marginBottom: 16 }}><Inputplaceholder="搜索用戶"value={searchValue}onChange={(e) => setSearchValue(e.target.value)}style={{ width: 200, marginRight: 8 }}onPressEnter={handleSearch}/><Button type="primary" onClick={handleSearch}>搜索</Button></div>{loading ? (<div>加載中...</div>) : (<div>{data?.list?.map((user) => (<divkey={user.id}style={{padding: "8px",border: "1px solid #ddd",marginBottom: "8px",}}><strong>{user.name}</strong> - {user.email}</div>))}<div style={{ marginTop: 16 }}><Buttondisabled={pagination.current === 1}onClick={() => pagination.changeCurrent(pagination.current - 1)}>上一頁</Button><span style={{ margin: "0 16px" }}>第 {pagination.current} 頁,共 {pagination.total} 條</span><Buttondisabled={pagination.current >= pagination.totalPages}onClick={() => pagination.changeCurrent(pagination.current + 1)}>下一頁</Button></div></div>)}</div>);
};

useDynamicList – 動態列表

import React from "react";
import { useDynamicList } from "ahooks";
import { Button, Input, Card } from "antd";const DynamicListExample = () => {const { list, remove, getKey, insert, move, replace, reset } = useDynamicList([{ name: "張三", age: 25 },{ name: "李四", age: 30 },{ name: "王五", age: 28 },]);const [inputName, setInputName] = React.useState("");const [inputAge, setInputAge] = React.useState("");const handleAdd = () => {if (inputName && inputAge) {insert(0, { name: inputName, age: parseInt(inputAge) });setInputName("");setInputAge("");}};return (<div><div style={{ marginBottom: 16 }}><Inputplaceholder="姓名"value={inputName}onChange={(e) => setInputName(e.target.value)}style={{ width: 120, marginRight: 8 }}/><Inputplaceholder="年齡"value={inputAge}onChange={(e) => setInputAge(e.target.value)}style={{ width: 80, marginRight: 8 }}/><Button type="primary" onClick={handleAdd}>添加到開頭</Button><Button onClick={reset} style={{ marginLeft: 8 }}>重置</Button></div>{list.map((item, index) => (<Cardkey={getKey(index)}size="small"style={{ marginBottom: 8 }}extra={<div><Buttonsize="small"onClick={() => move(index, index - 1)}disabled={index === 0}>上移</Button><Buttonsize="small"onClick={() => move(index, index + 1)}disabled={index === list.length - 1}style={{ marginLeft: 4 }}>下移</Button><Buttonsize="small"dangeronClick={() => remove(index)}style={{ marginLeft: 4 }}>刪除</Button></div>}><p><strong>姓名:</strong> {item.name}</p><p><strong>年齡:</strong> {item.age}</p></Card>))}</div>);
};

useVirtualList – 虛擬列表

import React, { useMemo, useRef } from "react";
import { useVirtualList } from "ahooks";export default function Demo() {const containerRef = useRef(null);const wrapperRef = useRef(null);// 生成大量測試數據const originalList = useMemo(() => {return Array.from({ length: 10000 }, (_, index) => ({id: index,title: `列表項 ${index + 1}`,content: `這是第 ${index + 1} 個列表項的內容,包含一些示例文本。`,timestamp: new Date(Date.now() - Math.random() * 10000000000).toLocaleString(),}));}, []);// 使用 useVirtualList hook - 正確版本const [list] = useVirtualList(originalList, {containerTarget: containerRef,wrapperTarget: wrapperRef,itemHeight: 80,overscan: 10,});console.log("originalList length:", originalList.length);console.log("virtual list length:", list.length);console.log("containerRef:", containerRef);console.log("wrapperRef:", wrapperRef);// 計算總高度const totalHeight = originalList.length * 80; // 每個項目80px高度console.log("totalHeight:", totalHeight);console.log("list first item:", list?.[0]);// 如果虛擬列表不工作,先顯示普通列表const showNormalList = !list || list.length === 0;return (<div className="p-6 max-w-4xl mx-auto"><h1 className="text-3xl font-bold text-gray-800 mb-6">useVirtualList 虛擬列表示例</h1><div className="mb-4 text-sm text-gray-600">總共 {originalList.length} 個列表項,但只渲染可見區域的項目{showNormalList && (<span className="text-orange-600"> (使用普通列表作為備用)</span>)}</div>{/* 虛擬列表容器 */}<divref={containerRef}className="border border-gray-200 rounded-lg overflow-y-auto bg-white shadow-sm"style={{ height: "600px" }}><div ref={wrapperRef}>{showNormalList? // 備用:普通列表originalList.slice(0, 20).map((item) => (<divkey={item.id}className="border-b border-gray-100 p-4 hover:bg-gray-50 transition-colors"style={{ height: "80px" }}><div className="flex items-center justify-between"><div className="flex-1"><h3 className="font-semibold text-gray-800 mb-1">{item.title}</h3><p className="text-sm text-gray-600 line-clamp-2">{item.content}</p></div><div className="text-xs text-gray-400 ml-4">{item.timestamp}</div></div></div>)): // 虛擬列表list.map((item) => (<divkey={item.index}className="border-b border-gray-100 p-4 hover:bg-gray-50 transition-colors"style={{ height: "80px" }}><div className="flex items-center justify-between"><div className="flex-1"><h3 className="font-semibold text-gray-800 mb-1">{item.data.title}</h3><p className="text-sm text-gray-600 line-clamp-2">{item.data.content}</p></div><div className="text-xs text-gray-400 ml-4">{item.data.timestamp}</div></div></div>))}</div></div></div>);
}

6. useHistoryTravel – 歷史記錄

import React from "react";
import { useHistoryTravel } from "ahooks";
import { Button, Input, Card } from "antd";const HistoryTravelExample = () => {const { value, setValue, backLength, forwardLength, back, forward, reset } =useHistoryTravel("");const handleChange = (e) => {setValue(e.target.value);};return (<div><Card title="歷史記錄管理" style={{ marginBottom: 16 }}><div style={{ marginBottom: 16 }}><Inputvalue={value}onChange={handleChange}placeholder="輸入內容,每次修改都會記錄歷史"style={{ marginBottom: 8 }}/><div><Button onClick={reset} style={{ marginRight: 8 }}>重置</Button><span style={{ color: "#666" }}>當前值: {value || "(空)"}</span></div></div><div style={{ marginBottom: 16 }}><Buttondisabled={backLength <= 0}onClick={back}style={{ marginRight: 8 }}>后退 ({backLength})</Button><Buttondisabled={forwardLength <= 0}onClick={forward}style={{ marginRight: 8 }}>前進 ({forwardLength})</Button></div></Card><Card title="歷史記錄信息"><p><strong>可后退步數:</strong> {backLength}</p><p><strong>可前進步數:</strong> {forwardLength}</p><p><strong>總歷史記錄數:</strong> {backLength + forwardLength + 1}</p></Card></div>);
};

useNetwork – 網絡狀態

import React from "react";
import { useNetwork } from "ahooks";
import { Card, Tag, Alert } from "antd";const NetworkExample = () => {const network = useNetwork();const getNetworkStatus = () => {if (network.online) {return <Tag color="green">在線</Tag>;}return <Tag color="red">離線</Tag>;};const getNetworkType = () => {if (network.effectiveType) {return <Tag color="blue">{network.effectiveType}</Tag>;}return <Tag color="orange">未知</Tag>;};return (<div><Card title="網絡狀態監控"><div style={{ marginBottom: 16 }}><strong>連接狀態:</strong> {getNetworkStatus()}</div><div style={{ marginBottom: 16 }}><strong>網絡類型:</strong> {getNetworkType()}</div>{!network.online && (<Alertmessage="網絡連接已斷開"description="請檢查您的網絡連接,某些功能可能無法正常使用。"type="warning"showIconstyle={{ marginBottom: 16 }}/>)}<Card title="詳細網絡信息" size="small"><p><strong>在線狀態:</strong> {network.online ? "是" : "否"}</p><p><strong>網絡類型:</strong> {network.effectiveType || "未知"}</p><p><strong>下行速度:</strong>{" "}{network.downlink ? `${network.downlink} Mbps` : "未知"}</p><p><strong>往返時間:</strong>{" "}{network.rtt ? `${network.rtt} ms` : "未知"}</p><p><strong>保存數據模式:</strong> {network.saveData ? "是" : "否"}</p></Card></Card></div>);
};

useSelections – 多選管理

import React, { useMemo } from "react";
import { useSelections } from "ahooks";
import { Checkbox, Button, Card, List } from "antd";const SelectionsExample = () => {const list = useMemo(() => [{ id: 1, name: "蘋果", price: 5.5 },{ id: 2, name: "香蕉", price: 3.2 },{ id: 3, name: "橙子", price: 4.8 },{ id: 4, name: "葡萄", price: 8.9 },{ id: 5, name: "草莓", price: 12.5 },{ id: 6, name: "藍莓", price: 15.8 },],[]);const {selected,allSelected,isSelected,toggle,toggleAll,partiallySelected,} = useSelections(list, {defaultSelected: [list[0], list[2]], // 默認選中第一個和第三個項});const totalPrice = selected.map((item) => item.price || 0).reduce((sum, price) => sum + price, 0);// 調試信息console.log("selected:", selected);console.log("allSelected:", allSelected);console.log("partiallySelected:", partiallySelected);console.log("list:", list);return (<div><divstyle={{marginBottom: 16,padding: "10px",backgroundColor: "#f5f5f5",borderRadius: "4px",}}><strong>當前選中項 ID:</strong>{" "}{selected.map((item) => item.id).join(", ") || "無"}</div><Card title="多選管理示例" style={{ marginBottom: 16 }}><div style={{ marginBottom: 16 }}><Checkboxchecked={allSelected}onClick={toggleAll}indeterminate={partiallySelected}style={{ marginRight: 8 }}>全選</Checkbox><span style={{ color: "#666" }}>已選擇 {selected.length} 項,總價: ¥{totalPrice.toFixed(2)}</span></div><ListdataSource={list}renderItem={(item) => (<List.Itemstyle={{display: "flex",justifyContent: "space-between",alignItems: "center",padding: "8px 0",borderBottom: "1px solid #f0f0f0",}}><div style={{ display: "flex", alignItems: "center" }}><Checkboxchecked={isSelected(item)}onClick={() => toggle(item)}style={{ marginRight: 8 }}/><span>{item.name}</span></div><span style={{ color: "#666" }}>¥{item.price}</span></List.Item>)}/></Card></div>);
};

useCountDown – 倒計時

import React, { useState } from "react";
import { useCountDown } from "ahooks";
import { Button, Card, Input, message } from "antd";const SmsCountDownExample = () => {const [phoneNumber, setPhoneNumber] = useState("");const [targetDate, setTargetDate] = useState();const [countdown] = useCountDown({targetDate,onEnd: () => {console.log("倒計時結束!");message.success("倒計時結束,可以重新發送短信");},});const formatTime = (ms) => {const seconds = Math.floor(ms / 1000);return seconds.toString().padStart(2, "0");};const handleSendSms = () => {if (!phoneNumber) {message.error("請輸入手機號碼");return;}if (phoneNumber.length !== 11) {message.error("請輸入正確的11位手機號碼");return;}// 模擬發送短信message.success(`驗證碼已發送到 ${phoneNumber}`);// 開始60秒倒計時setTargetDate(Date.now() + 60000);};const handleReset = () => {setTargetDate(undefined);};return (<div><Card title="短信驗證碼倒計時" style={{ marginBottom: 16 }}><div style={{ marginBottom: 16 }}><Inputplaceholder="請輸入手機號碼"value={phoneNumber}onChange={(e) => setPhoneNumber(e.target.value)}style={{ marginBottom: 8 }}maxLength={11}/><div style={{ display: "flex", alignItems: "center", gap: 8 }}><Buttontype="primary"onClick={handleSendSms}disabled={countdown !== 0}style={{ flex: 1 }}>{countdown === 0? "發送驗證碼": `重新發送(${formatTime(countdown)}s)`}</Button>{countdown !== 0 && (<Button onClick={handleReset} size="small">重置</Button>)}</div></div></Card></div>);
};

useCounter – 計數器

import React from "react";
import { useCounter } from "ahooks";
import { Button, Card, InputNumber, Space } from "antd";const CounterExample = () => {const [current, { inc, dec, set, reset }] = useCounter(1, {min: 1,max: 10,});return (<div><Card title="useCounter 計數器示例" style={{ marginBottom: 16 }}><div style={{ textAlign: "center", marginBottom: 16 }}><divstyle={{ fontSize: "32px", fontWeight: "bold", color: "#1890ff" }}>{current}</div></div><div style={{ textAlign: "center", marginBottom: 16 }}><Space><Buttontype="primary"onClick={() => inc()}style={{ marginRight: 8 }}>inc(1)</Button><Button onClick={() => dec()} style={{ marginRight: 8 }}>dec(1)</Button><Button onClick={() => set(3)} style={{ marginRight: 8 }}>set(3)</Button><Button onClick={reset} style={{ marginRight: 8 }}>reset(0)</Button></Space></div><div style={{ textAlign: "center" }}><Space><InputNumbermin={1}max={10}value={current}onChange={(value) => set(value || 1)}style={{ width: 100 }}/><span style={{ color: "#666" }}>直接輸入數值</span></Space></div></Card></div>);
};

useTextSelection – 文本選擇

import React from "react";
import { useTextSelection } from "ahooks";
import { Card } from "antd";const TextSelectionExample = () => {const selection = useTextSelection();return (<div><Card title="文本選擇監聽" style={{ marginBottom: 16 }}><divstyle={{padding: "16px",border: "1px solid #d9d9d9",borderRadius: "6px",backgroundColor: "#fafafa",lineHeight: "1.8",}}><p>這是一段示例文本,您可以在這里選擇任意內容。選擇文本后,下方會顯示選擇的相關信息,包括選中的文本內容、選擇的位置信息等。這個功能在需要獲取用戶選擇的文本內容時非常有用,比如實現文本高亮、復制選中內容等功能。</p><p>您可以嘗試選擇單個單詞、短語或者整段文本,觀察下方信息的變化。選擇不同的文本內容,會得到不同的選擇結果。</p></div></Card><Card title="選擇信息" size="small" style={{ marginBottom: 16 }}>{selection.text ? (<div><p><strong>選中的文本:</strong></p><divstyle={{padding: "8px",backgroundColor: "#f0f0f0",borderRadius: "4px",marginBottom: "8px",wordBreak: "break-all",}}>"{selection.text}"</div>{selection.rects && selection.rects.length > 0 && (<div><p><strong>選擇區域:</strong></p><div style={{ fontSize: "12px", color: "#666" }}><p>區域數量: {selection.rects.length}</p>{selection.rects.map((rect, index) => (<p key={index}>區域 {index + 1}: x={rect.x.toFixed(0)}, y={rect.y.toFixed(0)}, 寬={rect.width.toFixed(0)}, 高={rect.height.toFixed(0)}</p>))}</div></div>)}</div>) : (<div style={{ color: "#999", textAlign: "center" }}>請在上方文本中選擇內容</div>)}</Card></div>);
};

useWebSocket – WebSocket 連接

import React, { useState } from "react";
import { useWebSocket } from "ahooks";
import { Button, Card, Input, List, Tag, Alert } from "antd";const WebSocketExample = () => {const [url, setUrl] = useState("ws://localhost:8080");const [message, setMessage] = useState("");const { readyState, sendMessage, latestMessage, disconnect, connect } =useWebSocket(url, {onOpen: () => {console.log("WebSocket連接成功");},onMessage: (message) => {console.log("收到消息:", message);},onError: (error) => {console.log("WebSocket錯誤:", error);},onClose: () => {console.log("WebSocket連接關閉");},manual: true, // 手動連接});const [messageHistory, setMessageHistory] = useState([]);React.useEffect(() => {if (latestMessage) {setMessageHistory((prev) => [...prev,{id: Date.now(),content: latestMessage.data,type: "received",time: new Date().toLocaleTimeString(),},]);}}, [latestMessage]);const handleSend = () => {if (message.trim()) {sendMessage(message);setMessageHistory((prev) => [...prev,{id: Date.now(),content: message,type: "sent",time: new Date().toLocaleTimeString(),},]);setMessage("");}};const getStatusText = () => {switch (readyState) {case 0:return { text: "連接中", color: "processing" };case 1:return { text: "已連接", color: "success" };case 2:return { text: "關閉中", color: "warning" };case 3:return { text: "已關閉", color: "error" };default:return { text: "未知", color: "default" };}};const status = getStatusText();return (<div><Card title="WebSocket 連接管理" style={{ marginBottom: 16 }}><div style={{ marginBottom: 16 }}><Inputvalue={url}onChange={(e) => setUrl(e.target.value)}placeholder="WebSocket URL"style={{ marginBottom: 8 }}/><div><Buttontype="primary"onClick={connect}disabled={readyState === 1}style={{ marginRight: 8 }}>連接</Button><ButtononClick={disconnect}disabled={readyState !== 1}style={{ marginRight: 8 }}>斷開</Button><Tag color={status.color}>狀態: {status.text}</Tag></div></div>{readyState === 3 && (<Alertmessage="連接已斷開"description="請點擊連接按鈕重新建立WebSocket連接"type="warning"showIconstyle={{ marginBottom: 16 }}/>)}</Card><Card title="消息收發" style={{ marginBottom: 16 }}><div style={{ marginBottom: 16 }}><Input.TextAreavalue={message}onChange={(e) => setMessage(e.target.value)}placeholder="輸入要發送的消息"rows={3}style={{ marginBottom: 8 }}onPressEnter={(e) => {if (!e.shiftKey) {e.preventDefault();handleSend();}}}/><Buttontype="primary"onClick={handleSend}disabled={readyState !== 1 || !message.trim()}>發送消息</Button></div><Listsize="small"dataSource={messageHistory}renderItem={(item) => (<List.Itemstyle={{padding: "8px 0",borderBottom: "1px solid #f0f0f0",}}><div style={{ width: "100%" }}><divstyle={{display: "flex",justifyContent: "space-between",marginBottom: "4px",}}><Tag color={item.type === "sent" ? "blue" : "green"}>{item.type === "sent" ? "發送" : "接收"}</Tag><span style={{ fontSize: "12px", color: "#666" }}>{item.time}</span></div><divstyle={{padding: "8px",backgroundColor:item.type === "sent" ? "#e6f7ff" : "#f6ffed",borderRadius: "4px",wordBreak: "break-all",}}>{item.content}</div></div></List.Item>)}/></Card><Card title="連接信息" size="small"><p><strong>連接狀態:</strong><Tag color={status.color}>{status.text}</Tag></p><p><strong>連接URL:</strong> {url}</p><p><strong>消息總數:</strong> {messageHistory.length}</p><p><strong>最后消息:</strong> {latestMessage?.data || "無"}</p></Card></div>);
};

useTheme – 主題

import React from "react";
import { useTheme } from "ahooks";
import { Button, Card, Tag } from "antd";const ThemeExample = () => {const { theme, themeMode, setThemeMode } = useTheme({localStorageKey: "themeMode",});return (<div><Card title="useTheme 基礎用法" style={{ marginBottom: 16 }}><div style={{ marginBottom: 16 }}><p><strong>theme:</strong> <Tag color="blue">{theme}</Tag></p><p><strong>themeMode:</strong> <Tag color="green">{themeMode}</Tag></p></div><div style={{ marginBottom: 16 }}><Buttontype="primary"onClick={() => setThemeMode("dark")}style={{ marginRight: 8 }}>使用深色主題</Button><ButtononClick={() => setThemeMode("light")}style={{ marginRight: 8 }}>使用淺色主題</Button><ButtononClick={() => setThemeMode("system")}style={{ marginRight: 8 }}>跟隨系統</Button></div><divstyle={{padding: "16px",border: "1px solid #d9d9d9",borderRadius: "6px",backgroundColor: theme === "dark" ? "#141414" : "#ffffff",color: theme === "dark" ? "#ffffff" : "#000000",transition: "all 0.3s ease",}}><h3 style={{ marginBottom: 12 }}>主題預覽區域</h3><p>這是一個主題預覽區域,展示了當前主題的樣式效果。 當前主題: {theme},主題模式: {themeMode}</p></div></Card></div>);
};

通過合理使用這些 hooks,可以大大簡化 React 應用的開發復雜度,提高代碼的可維護性和用戶體驗。

場景類 hooks 速查表

Hook 名稱用途描述
useAntdTableAntd 表格集成專門為 Ant Design Table 組件設計的 hook,簡化表格數據獲取和分頁管理
useFusionTableFusion 表格集成專門為 Fusion Design Table 組件設計的 hook,提供表格數據管理功能
useInfiniteScroll無限滾動實現無限滾動加載,支持觸底加載更多數據,自動處理加載狀態
usePagination分頁管理簡化分頁數據的獲取和管理,自動處理頁碼和頁面大小的狀態
useDynamicList動態列表管理動態增減的列表項,支持添加、刪除、移動等操作
useVirtualList虛擬列表實現大數據量的虛擬滾動列表,提升性能,減少 DOM 節點數量
useHistoryTravel歷史記錄管理狀態的歷史記錄,支持前進、后退、跳轉到指定歷史點
useNetwork網絡狀態監聽網絡連接狀態變化,包括在線/離線狀態和網絡類型
useSelections多選管理管理列表的多選狀態,支持全選、反選、批量操作等功能
useCountDown倒計時實現倒計時功能,支持自定義格式和回調函數
useCounter計數器管理數字計數器的增刪改查操作,支持步長設置
useTextSelection文本選擇監聽用戶文本選擇事件,獲取選中的文本內容和位置信息
useWebSocketWebSocket 連接管理 WebSocket 連接,處理連接、斷開、消息收發等操作
useTheme主題管理管理應用主題狀態,支持主題切換和持久化存儲

?React強大且靈活hooks庫——ahooks入門實踐之場景類(scene)hook詳解 - 高質量源碼分享平臺-免費下載各類網站源碼與模板及前沿動態資訊

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88750.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88750.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88750.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大模型之Langchain篇(二)——RAG

寫在前面 跟著樓蘭老師學習【LangChain教程】2025吃透LangChain框架快速上手與深度實戰&#xff0c;全程干貨無廢話&#xff0c;三天學完&#xff0c;讓你少走百分之99彎路&#xff01;_嗶哩嗶哩_bilibili 計算相似度 一般用的余弦相似度&#xff0c;這里只是演示計算。 fr…

深入理解圖像二值化:從靜態圖像到視頻流實時處理

一、引言&#xff1a;圖像分析&#xff0c;從“黑與白”開始在計算機視覺任務中&#xff0c;**圖像二值化&#xff08;Image Binarization&#xff09;**是最基礎也是最關鍵的圖像預處理技術之一。它通過將灰度圖像中每個像素轉換為兩個離散值&#xff08;通常是0和255&#xf…

云蝠智能 VoiceAgent重構企業呼入場景服務范式

在數字化轉型浪潮中&#xff0c;企業呼入場景面臨客戶服務需求激增與人力成本攀升的雙重挑戰。傳統呼叫中心日均處理僅 300-500 通電話&#xff0c;人力成本占比超 60%&#xff0c;且服務質量受情緒波動影響顯著。云蝠智能推出的 VoiceAgent 語音智能體&#xff0c;通過全棧自研…

java進階(一)+學習筆記

1.JAVA設計模式1.1 什么是設計模式設計模式是軟件開發過程中前輩們在長期實踐中針對重復出現的問題總結出來的最佳解決方案。這些模式不是具體的代碼實現&#xff0c;而是經過驗證的、可重用的設計思想&#xff0c;能夠幫助開發者更高效地解決特定類型的問題。設計模式的重要性…

Pandas-數據清洗與處理

Pandas-數據清洗與處理一、數據清洗的核心目標二、缺失值處理1. 缺失值檢測2. 缺失值處理策略&#xff08;1&#xff09;刪除法&#xff08;2&#xff09;填充法三、異常值識別與處理1. 異常值檢測方法&#xff08;1&#xff09;統計法&#xff08;2&#xff09;業務規則法2. 異…

在 MacOS 上安裝和配置 Kafka

消息代理是一種軟件&#xff0c;充當在不同應用程序之間發送消息的中介。它的功能類似于服務器&#xff0c;從一個應用程序&#xff08;稱為生產者&#xff09;接收消息&#xff0c;并將其路由到一個或多個其他應用程序&#xff08;稱為消費者&#xff09;。消息代理的主要目的…

基于Leaflet調用天地圖在線API的多層級地名檢索實戰

目錄 前言 一、天地圖在線檢索 1、在線檢索功能 2、再談后后接口 二、Leaflet多層級實現實例 1、層級調用實現原理 2、Leaflet中多層級調用 3、成果展示 三、總結 前言 “地圖是世界的索引&#xff0c;而地名則是索引中的索引。”當互聯網地圖進入 Web 2.0 時代&#x…

基于Prompt結構的語校解析:3H日本語學校信息建模實錄(4/500)

基于Prompt結構的語校解析&#xff1a;3H日本語學校信息建模實錄&#xff08;4/500&#xff09; 系列延續&#xff1a;500所日本語言學校結構數據工程 關鍵詞&#xff1a;招生結構、JLPTEJU、國籍比例、認定校、Prompt訓練集 一、我們在構建什么樣的語言學校語料&#xff1f; …

Leaflet面試題及答案(61-80)

查看本專欄目錄 文章目錄 ?? 面試問題及答案(61-80)61. 如何在地圖上顯示一個動態更新的圖層?62. 如何實現地圖上的熱力圖(Heatmap)?63. 如何自定義地圖控件的位置?64. 如何處理地圖加載失敗的情況?65. 如何實現地圖的離線功能?66. 如何將地圖導出為圖片?67. 如何實…

MIG_IP核的時鐘系統

MIG_IP核的時鐘系統時鐘的種類和配置時鐘的種類和配置 整體框圖 DDR_PHY_CLK&#xff1a;DDR3的工作頻率&#xff0c;用來得到想要的線速率。假設此時鐘為800M&#xff0c;那么DDR雙沿采樣&#xff0c;線速率為1600Mbit&#xff1b; UI_CLK&#xff1a;DDR_PHY_CLK的四分之一…

若依框架集成阿里云OSS實現文件上傳優化

背景介紹 在若依框架目前的實現中&#xff0c;是把圖片存儲到了服務器本地的目錄&#xff0c;通過服務進行訪問&#xff0c;這樣做存儲的是比較省事&#xff0c;但是缺點也有很多&#xff1a; 硬件與網絡要求&#xff1a;服務器通常需要高性能的硬件和穩定的網絡環境&#xff0…

Mac如何連接惠普M126a打印機(教程篇)

這里寫自定義目錄標題Mac如何連接惠普M126a打印機&#xff08;教程篇&#xff09;教程配置如下&#xff1a;Mac如何連接惠普M126a打印機&#xff08;教程篇&#xff09; 惠普M126a連接Mac&#xff08;教程篇&#xff09; 教程配置如下&#xff1a; 首先&#xff0c;先獲取與HP打…

感恩日記:記錄生活中的美好時刻

感恩日記的landing page登錄注冊填寫感恩事項私信可以體驗一下

一扇門鈴,萬向感應——用 eventfd 實現零延遲通信

&#x1f50d; 本篇概要 eventfd 是 Linux 提供的一種輕量級事件通知機制。你可以把它想象成一個“計數器盒子”。它里面維護的是一個64位的計數器。寫入&#xff1a;往盒子里放一些數字&#xff08;比如 1、5、10&#xff09;&#xff0c;表示有幾件事發生了。讀取&#xff1a…

基于Node.js的線上教學系統的設計與實現(源碼+論文+調試+安裝+售后)

感興趣的可以先收藏起來&#xff0c;還有大家在畢設選題&#xff0c;項目以及論文編寫等相關問題都可以給我留言咨詢&#xff0c;我會一一回復&#xff0c;希望幫助更多的人。系統背景近年來&#xff0c;全球數字化浪潮的推進與教育公平化需求的增長&#xff0c;促使線上教學迎…

互斥鎖詳解(操作系統os)

1. 互斥鎖 (Mutex) - 檔案室的“智能鎖”首先&#xff0c;我們給之前討論的那些“鎖”一個正式的名字&#xff1a;互斥鎖 (Mutex)。概念&#xff1a;你可以把它簡單理解成檔案室門上的一把“智能鎖”。它只有兩種狀態&#xff1a;locked (已上鎖) 或 unlocked (未上鎖)。操作&a…

自動潤滑系統:從 “盲目養護“ 到智能精注的工業運維革命

?在工業運維的漫長歷史中&#xff0c;傳統潤滑模式如同"定時喂飯"——無論設備實際需求&#xff0c;僅憑經驗或固定周期執行潤滑作業。這種模式埋下兩大隱患&#xff1a;過度潤滑&#xff1a;某汽車生產線曾因季度性強制潤滑&#xff0c;每年浪費1.2噸潤滑脂&#x…

【Java八股文總結 — 包學會】(二)計算機網絡

1.一條url輸入到瀏覽器最后顯示頁面的過程 URL解析與處理 瀏覽器解析URL&#xff08;如https://www.example.com/page&#xff09; 分離協議&#xff08;https&#xff09;、域名&#xff08;www.example.com&#xff09;和資源路徑&#xff08;/page&#xff09; 檢查HSTS預加…

力扣61.旋轉鏈表

給你一個鏈表的頭節點 head &#xff0c;旋轉鏈表&#xff0c;將鏈表每個節點向右移動 k 個位置。示例 1&#xff1a;輸入&#xff1a;head [1,2,3,4,5], k 2 輸出&#xff1a;[4,5,1,2,3]示例 2&#xff1a;輸入&#xff1a;head [0,1,2], k 4 輸出&#xff1a;[2,0,1]提示…

深度剖析:std::vector 內存機制與 push_back 擴容策略

深度剖析&#xff1a;std::vector 內存機制與 push_back 擴容策略 1. std::vector 核心內部結構 #mermaid-svg-8HOj3MqsD6UVgEeA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-8HOj3MqsD6UVgEeA .error-icon{fill:…