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 项目提升开发效率的重要工具。

相关推荐
shizhenshide3 小时前
如何在同一站点支持多版本的 reCAPTCHA 的兼容性方案
服务器·前端·网络·安全·captcha·ezcaptcha
CodeCraft Studio3 小时前
借助Aspose.HTML控件,使用 Python 编程创建 HTML 页面
前端·python·html·aspose·python创建html·html sdk
前端OnTheRun3 小时前
React18学习笔记(三) ReactRouter--React中的路由,案例--记账本
react.js·路由·reactrouter
杨超越luckly3 小时前
HTML应用指南:利用GET请求获取全国奥迪授权经销商门店位置信息
大数据·前端·python·html·数据可视化·门店数据
05Nuyoah3 小时前
DAY 01 HTML的认识
前端·html
嚣张农民3 小时前
还在自己买服务器?试试 Amazon EC2,真香!
前端·后端·程序员
charlie1145141914 小时前
Chrome View渲染机制学习小记
前端·chrome·学习·渲染·gpu·客户端
多看书少吃饭4 小时前
vue3+TS 前端调用海康摄像头视频流,后端用 Node.js 做 RTSP 转 WebSocket-FLV 转发,并且前后端优化延迟方案
前端·websocket·node.js
艾小码4 小时前
别再层层传递props了!useContext让你的React组件通信如此简单
javascript·react.js·前端框架