ahooks:一套高质量、可靠的 React Hooks 库

1 什么是 ahooks

ahooks 是由阿里巴巴团队开发的一套高质量、可靠的 React Hooks 库,旨在通过封装常用业务逻辑,帮助开发者提升 React 应用开发效率。截至 2025 年 6 月,最新版本为 3.8.5,已在阿里内部数百个产品(如支付宝、淘宝、天猫)中投入生产使用,并支持服务器端渲染(SSR)、TypeScript 类型定义等企业级特性。

与社区其他 Hooks 库(如 react-use)相比,ahooks 的核心优势在于:

  • 贴近业务场景 :提炼自阿里中台业务,提供如 useAntdTableusePagination 等高频场景 Hooks
  • 无闭包陷阱:所有输出函数引用地址固定,输入函数自动获取最新值
  • 插件化设计 :核心功能(如 useRequest)采用插件架构,支持按需扩展
  • 严格兼容性:解决 React 严格模式(Strict Mode)和热更新(HMR)下的常见问题

2 安装与基础使用

2.1 环境准备

ahooks 要求 React 版本 ≥ 16.8.0(支持 Hooks 的最低版本),推荐使用 npm 或 yarn 安装:

bash 复制代码
# npm
npm install ahooks --save

# yarn
yarn add ahooks

# pnpm
pnpm add ahooks

2.2 快速上手

以最常用的 useRequest 为例,实现一个数据请求组件:

jsx 复制代码
import { useRequest } from 'ahooks'

function UserProfile() {
  const { data, loading, error } = useRequest(
    () => fetch('/api/user').then(res => res.json()),
    {
      refreshDeps: [], // 依赖变化时自动刷新
      onSuccess: (result) => {
        console.log('请求成功:', result)
      }
    }
  )

  if (loading) return <div>加载中...</div>
  if (error) return <div>错误: {error.message}</div>
  
  return (
    <div>
      <h2>{data.name}</h2>
      <p>邮箱: {data.email}</p>
    </div>
  )
}

3 核心 Hooks 分类详解

3.1 状态管理 Hooks

3.1.1 useToggle:双向状态切换

简化 boolean 或双值状态切换逻辑,避免手动编写 setState(!state)

jsx 复制代码
import { useToggle } from 'ahooks'

function ThemeSwitch() {
  // 基础用法(布尔值)
  const [darkMode, { toggle }] = useToggle(false)
  
  // 自定义值切换
  const [status, { setLeft, setRight }] = useToggle('online', 'offline')

  return (
    <div>
      <button onClick={toggle}>
        {darkMode ? '切换至亮色' : '切换至暗色'}
      </button>
      <div>当前状态: {status}</div>
      <button onClick={setLeft}>上线</button>
      <button onClick={setRight}>下线</button>
    </div>
  )
}

3.1.2 useLocalStorageState:持久化状态

将状态存储在 localStorage 中,页面刷新后自动恢复:

jsx 复制代码
import { useLocalStorageState } from 'ahooks'

function SearchHistory() {
  const [history, setHistory] = useLocalStorageState('search_history', {
    defaultValue: []
  })

  const addSearch = (keyword) => {
    setHistory(prev => [...new Set([keyword, ...prev])].slice(0, 10))
  }

  return (
    <div>
      <input 
        placeholder="搜索..."
        onKeyPress={(e) => {
          if (e.key === 'Enter') addSearch(e.target.value)
        }}
      />  
      <ul>
        {history.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  )
}

3.2 副作用处理 Hooks

3.2.1 useRequest:全能请求管理

ahooks 的明星 Hooks,封装了请求状态管理、缓存、轮询等 20+ 功能:

jsx 复制代码
import { useRequest } from 'ahooks'

function ProductList() {
  const { 
    data, 
    loading, 
    run, 
    refresh 
  } = useRequest(
    ({ current, pageSize, keyword }) => 
      fetch(`/api/products?current=${current}&pageSize=${pageSize}&keyword=${keyword}`)
        .then(res => res.json()),
    {
      manual: true, // 手动触发
      defaultParams: [{ current: 1, pageSize: 10, keyword: '' }],
      debounceInterval: 300, // 防抖
      cacheKey: 'productList', // 缓存键
      revalidateOnFocus: true, // 窗口聚焦时刷新
    }
  )

  return (
    <div>
      <input 
        placeholder="搜索产品"
        onChange={(e => {
          run({ ...run.params[0], keyword: e.target.value })
        })}
      />
      <button onClick={refresh}>刷新</button>
      {loading ? <div>加载中...</div> : (
        <table>
          {/* 表格内容 */}
        </table>
      )}
    </div>
  )
}

3.2.2 useDebounce:值防抖处理

延迟处理高频变化的值(如搜索输入):

jsx 复制代码
import { useDebounce, useState } from 'ahooks'

function SearchBox() {
  const [inputValue, setInputValue] = useState('')
  // 延迟 500ms 处理输入值
  const debouncedValue = useDebounce(inputValue, { wait: 500 })

  // 仅在防抖值变化时触发搜索
  useEffect(() => {
    if (debouncedValue) {
      searchApi(debouncedValue)
    }
  }, [debouncedValue])

  return (
    <input
      value={inputValue}
      onChange={(e) => setInputValue(e.target.value)}
      placeholder="输入搜索关键词"
    />
  )
}

3.3 DOM 操作 Hooks

3.3.1 useClickAway:点击外部关闭

检测点击事件是否发生在目标元素外部,常用于下拉菜单、模态框:

jsx 复制代码
import { useRef, useState } from 'react'
import { useClickAway } from 'ahooks'

function Dropdown() {
  const [visible, setVisible] = useState(false)
  const ref = useRef(null)

  // 点击外部区域关闭下拉菜单
  useClickAway(() => {
    setVisible(false)
  }, ref, ['click']) // 监听 click 事件

  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button onClick={() => setVisible(!visible)}>
        下拉菜单
      </button>
      {visible && (
        <div style={{ 
          position: 'absolute', 
          top: '100%', 
          width: '200px',
          border: '1px solid #ccc',
          padding: '8px'
        }}>
          <div>菜单项 1</div>
          <div>菜单项 2</div>
          <div>菜单项 3</div>
        </div>
      )}
    </div>
  )
}

3.3.2 useVirtualList:大数据列表优化

虚拟滚动列表,只渲染可视区域内的项,支持十万级数据渲染:

jsx 复制代码
import { useVirtualList } from 'ahooks'

function BigList() {
  // 生成 10 万条测试数据
  const data = Array.from({ length: 100000 }, (_, i) => ({
    id: i,
    content: `列表项 ${i + 1}`
  }))

  const { list, containerProps, wrapperProps } = useVirtualList(data, {
    itemHeight: 50, // 每行高度
    overscan: 5, // 视区外预渲染数量
  })

  return (
    <div 
      {...containerProps} 
      style={{ height: '500px', overflow: 'auto', border: '1px solid #ccc' }}
    >
      <div {...wrapperProps}>
        {list.map(item => (
          <div 
            key={item.id} 
            style={{ height: '50px', padding: '16px', borderBottom: '1px solid #eee' }}
          >
            {item.data.content}
          </div>
        ))}
      </div>
    </div>
  )
}

3.4 场景类 Hooks

3.4.1 useAntdTable:Ant Design 表格集成

无缝整合 Ant Design Table 组件,自动处理分页、排序、筛选逻辑:

jsx 复制代码
import { useAntdTable } from 'ahooks'
import { Table, Input, Button } from 'antd'

function UserTable() {
  const [form] = Form.useForm()
  
  const { tableProps, search } = useAntdTable(
    async (params) => {
      const { current, pageSize, ...rest } = params
      const res = await fetch('/api/users', {
        method: 'POST',
        body: JSON.stringify({ page: current, size: pageSize, ...rest })
      })
      const data = await res.json()
      return {
        list: data.records,
        total: data.total
      }
    },
    {
      form,
      defaultPageSize: 10
    }
  )

  return (
    <div>
      <Form form={form} layout="inline">
        <Form.Item name="username" 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: 'username' },
          { title: '邮箱', dataIndex: 'email' },
          { title: '注册时间', dataIndex: 'registerTime' }
        ]}
      />
    </div>
  )
}

4 高级特性与最佳实践

4.1 避免闭包陷阱

ahooks 对所有输入输出函数做了特殊处理,解决 React Hooks 常见的闭包问题:

jsx 复制代码
import { useInterval, useState } from 'ahooks'

function Timer() {
  const [count, setCount] = useState(0)
  
  // 即使没有将 count 加入依赖,也能获取最新值
  useInterval(() => {
    console.log('当前 count:', count) // 始终为最新值
  }, 1000)

  return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}

4.2 插件化请求能力

useRequest 通过插件机制实现丰富功能,如轮询、重试、缓存:

jsx 复制代码
// 轮询请求示例
const { data } = useRequest(fetchData, {
  pollingInterval: 5000, // 每 5 秒轮询一次
  pollingWhenHidden: false, // 页面隐藏时停止轮询
})

// 错误重试示例
const { data } = useRequest(fetchData, {
  retryCount: 3, // 失败重试 3 次
  retryInterval: 1000, // 重试间隔 1 秒
})

4.3 React 19 适配方案

虽然 ahooks 尚未官方支持 React 19,但可通过 package.json 临时适配:

json 复制代码
{
  "overrides": {
    "ahooks": {
      "react": "^19.0.0",
      "react-dom": "^19.0.0"
    }
  }
}

⚠️ 注意:React 19 中移除了 element.ref,可能导致部分 DOM 类 Hooks 出现警告,建议关注官方更新。

5 总结与资源

ahooks 作为成熟的 React Hooks 库,通过封装通用逻辑,显著减少了重复代码量(据统计平均减少 30%+ 状态管理代码)。其核心价值在于:

  1. 提升开发效率:无需重复实现防抖、节流、请求缓存等逻辑
  2. 保证代码质量:经过阿里内部数百个项目验证,处理了边缘场景
  3. 降低维护成本:统一的 API 设计,完善的 TypeScript 类型

官方资源

通过合理使用 ahooks,开发者可以将精力集中在业务逻辑而非基础功能实现上,是 React 项目提升开发效率的重要工具。

相关推荐
blackorbird3 小时前
Edge 浏览器 IE 模式成攻击突破口:黑客借仿冒网站诱导攻击
前端·edge
谷歌开发者4 小时前
Web 开发指向标 | Chrome 开发者工具学习资源 (一)
前端·chrome·学习
名字越长技术越强4 小时前
Chrome和IE获取本机ip地址
前端
天***88964 小时前
Chrome 安装失败且提示“无可用的更新” 或 “与服务器的连接意外终止”,Chrome 离线版下载安装教程
前端·chrome
半梦半醒*5 小时前
zabbix安装
linux·运维·前端·网络·zabbix
清羽_ls5 小时前
React Hooks 核心规则&自定义 Hooks
前端·react.js·hooks
你的人类朋友5 小时前
“签名”这个概念是非对称加密独有的吗?
前端·后端·安全
西陵5 小时前
Nx带来极致的前端开发体验——任务缓存
前端·javascript·架构
10年前端老司机7 小时前
Promise 常见面试题(持续更新中)
前端·javascript
潘小安7 小时前
跟着 AI 学 (一)- shell 脚本
前端·ci/cd·vibecoding