普通视图

发现新文章,点击刷新页面。
今天 — 2026年3月1日首页

简单高效的状态管理方案:Hox + ahooks

作者 fe小陈
2026年2月28日 23:54

在 React 开发中,状态管理是一个绕不开的话题。随着应用规模的增长,组件之间的数据传递和状态同步会变得愈发复杂。如何选择一款合适的状态管理方案,直接影响着开发体验和代码可维护性。本文将带你梳理当前主流的状态管理方案,并重点推荐一套简洁高效的组合:Hox + ahooks

为什么需要状态管理

随着应用规模扩大,我们需要在不同组件之间共享数据。想象一下:用户在某个页面修改了头像,这个变化需要实时反映在导航栏、侧边栏等多个位置。如果没有统一的状态管理,就只能通过层层传递 props,代码冗余且难以维护。

状态管理有三个核心目标:统一管理——所有共享数据存储在可预测的位置;响应式更新——状态变化时依赖它的组件自动重渲染;可预测性——状态变化可控、可追踪。

React 中需要管理的状态分为三类:本地状态——组件内部 useState 管理,通常不跨组件共享;服务端状态——从 API 获取的数据,需要缓存、轮询等能力;全局状态——多组件共享的状态,如用户信息、主题、购物车等。

主流方案概览

React 生态中的状态管理方案百花齐放,各有各的设计哲学和适用场景。为了帮助大家建立一个整体认知,我们先来看一下主流方案的对比。

方案 学习成本 包体积 社区活跃度 适用场景
Redux Toolkit 中高 约12KB 非常高 大型企业级项目
Zustand 约1KB 中小型项目
Hox 约2KB 追求极简体验
useState + Context 0 内置 简单场景

从 npm 下载量来看,Redux 仍然占据主导地位,但 Zustand 的增长速度非常惊人,在 2024 年的 State of React 调研中,Zustand 的满意度和使用率都位居前列。值得注意的是,传统的 useState 配合 Context 仍然是很多开发者的首选,这说明在很多场景下,我们其实不需要引入额外的状态管理库。

Redux Toolkit

Redux 是 React 状态管理领域的鼻祖,核心理念是单向数据流和不可变状态。但原始 Redux 过度设计:繁琐的 action types、冗长的 reducers、重复的模板代码,让很多开发者望而却步。

Redux Toolkit 是官方推荐的新一代工具集,通过简化的 API 大大降低了门槛。核心包括:createSlice——在一个文件中定义 state、reducer 和 action;createAsyncThunk——处理异步逻辑;configureStore——简化 store 创建。

import { createSlice, configureStore } from '@reduxjs/toolkit'

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: (state) => { state.value += 1 },
    decrement: (state) => { state.value -= 1 },
  },
})

const store = configureStore({ reducer: counterSlice.reducer })
export const { increment, decrement } = counterSlice.actions

组件中使用 useSelector 和 useDispatch:

import { useSelector, useDispatch } from 'react-redux'
import { increment, decrement } from './store'

function Counter() {
  const count = useSelector((state) => state.counter.value)
  const dispatch = useDispatch()
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  )
}

Redux Toolkit 适合对状态管理有严格要求的大型项目,需要时间旅行调试、复杂中间件等高级特性。但如果项目规模不大,引入 Redux 可能带来不必要的复杂度。

Zustand + tanstack-query

Zustand 是一个轻量级的状态管理库,其名字在德语中意为“状态”。Zustand 的设计理念是极简主义,它没有 Redux 那么多约束性的概念,只需要几行代码就能创建一个可全局共享的状态。Zustand 使用 Hooks API 来创建和消费状态,这使得它与 React 的开发模式完美契合。

Zustand 的核心优势在于它的简洁性。创建一个 store 只需要调用 create 函数,传入一个返回状态和方法的函数即可。与 Redux 不同的是,Zustand 不需要 Provider 包裹,组件可以直接通过 Hook 来消费状态。这种设计大大减少了组件树的复杂度和不必要的重新渲染。

import { create } from 'zustand'

const useCounterStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))

function Counter() {
  const { count, increment, decrement } = useCounterStore()
  return (
    <div>
      <span>{count}</span>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  )
}

而 tanstack-query(原 React Query)则是专门用于管理服务端状态的神器。它解决了数据获取、缓存、同步、轮询等一系列常见的后端数据管理需求。tanstack-query 的核心理念是将服务端数据视为一种特殊的“状态”,它应该独立于 UI 状态来管理。通过内置的缓存机制、后台刷新、乐观更新等功能,tanstack-query 大大简化了前后端数据交互的复杂度。

Zustand + tanstack-query 的组合在 2024 年备受推崇,这种组合兼顾了全局状态管理和服务端数据管理的需求,且两者都保持了极简的 API 设计。对于中型项目来说,这是一个性价比极高的选择。

其他方案

mobx、valtio、jotai,略。

为什么推荐 Hox + ahooks

在众多状态管理方案中,我想特别推荐 Hox + ahooks 这个组合。Hox 是一个专注于状态共享的轻量级库,而 ahooks 则是阿里巴巴开源的高质量 React Hooks 库。两者结合,能够提供一种极其简洁、直观的状态管理体验。

Hox 的核心理念是“状态即模型,模型即 Hook”。这意味着你可以用编写普通 React Hook 的方式来编写状态模型,不需要学习任何新的概念。在 Hox 中,创建一个全局状态与创建一个本地状态几乎没有区别,这大大降低了状态管理的复杂度。当你需要将一个组件的本地状态改为全局共享状态时,只需要将 useState 替换成 Hox 提供的 createGlobalStore 函数即可。

这种设计的优势是显而易见的。首先,它几乎不需要额外的学习成本,熟悉 React Hooks 的开发者可以立即上手;其次,它支持 TypeScript 类型自动推断,无需手动声明复杂类型;最后,它的 API 设计与 React 思维高度一致,不会产生心智负担。

ahooks 则是 React Hooks 工具库的佼佼者,它提供了大量实用的 Hook,覆盖了状态管理、DOM 操作、网络请求、传感器等众多场景。ahooks 的特点是高质量、可靠性强,由阿里巴巴前端团队维护,已在大量生产项目中得到验证。特别值得一提的是,ahooks 完美支持 SSR,这对于需要支持服务端渲染的项目来说是重要优势。

Hox + ahooks 的组合完美互补:Hox 解决全局状态共享问题,ahooks 则提供了丰富的工具 Hook 来处理各类复杂场景。从本质上讲,ahooks 解决的是“怎么做”的问题,而 Hox 解决的是“在哪存”的问题,两者配合使用,能够覆盖绝大多数前端状态管理需求。

Hox 核心用法

了解了 Hox 的设计理念,接下来我们深入探讨它的具体用法。Hox 的 API 设计非常简洁,只有两个核心函数:createGlobalStore 用于创建状态模型,useModel 用于在组件中消费状态。

安装

npm install hox
# 或
yarn add hox
# 或
pnpm add hox

创建状态模型

使用 Hox 创建一个全局状态模型非常简单,只需要调用 createGlobalStore 函数并传入一个返回状态和方法的函数即可。这个函数的写法与普通的自定义 Hook 完全一致,你可以在其中使用 useState、useReducer、useEffect 等任何 React Hooks。

// models/useCounter.js
import { createGlobalStore } from 'hox'
import { useState } from 'react'

export default createGlobalStore(function useCounter() {
  const [count, setCount] = useState(0)

  const increment = () => setCount(c => c + 1)
  const decrement = () => setCount(c => c - 1)
  const reset = () => setCount(0)

  return {
    count,
    increment,
    decrement,
    reset
  }
})

这段代码看起来与普通的自定义 Hook 几乎一模一样,唯一的区别是使用了 createGlobalStore 函数进行包裹。createGlobalStore 函数会确保这个 Hook 返回的状态和方法能够在多个组件之间共享。

统一挂载全局状态

hox 的 createGlobalStore 生成的状态需要以组件的形式挂载的 react 树上。用 HoxRoot 包起来即可:

import { HoxRoot } from 'hox'

ReactDOM.render(
  <HoxRoot>
    <App />
  </HoxRoot>,
  domContainer
)

在组件中使用

在组件中使用 Hox 创建的状态同样简单,只需要导入对应的模型并调用即可:

import useCounter from '../models/useCounter'

function Counter() {
  const { count, increment, decrement, reset } = useCounter()

  return (
    <div>
      <h2>计数: {count}</h2>
      <button onClick={increment}>增加</button>
      <button onClick={decrement}>减少</button>
      <button onClick={reset}>重置</button>
    </div>
  )
}

可以看到,使用方式与普通 Hook 完全相同。Hox 会自动处理状态的共享和响应式更新,你不需要关心 Provider 的配置,也不需要担心状态泄漏到其他不相关的组件。

优化订阅

hox 的优化订阅是通过返回一个数组做浅比较,hook 本身还是全部返回的。

const { count } = useCounter(s => [s.count])

TypeScript 支持

Hox 对 TypeScript 提供了开箱即用的支持。当你使用 TypeScript 编写模型时,类型推断会自动完成,无需额外的类型声明:

// models/useCounter.ts
import { createGlobalStore } from 'hox'
import { useState } from 'react'

interface CounterState {
  count: number
  increment: () => void
  decrement: () => void
  reset: () => void
}

export default createGlobalStore<CounterState>(function useCounter() {
  const [count, setCount] = useState(0)

  const increment = () => setCount(c => c + 1)
  const decrement = () => setCount(c => c - 1)
  const reset = () => setCount(0)

  return {
    count,
    increment,
    decrement,
    reset
  }
})

不过,由于 Hox 采用了独特的类型推断机制,即使你不在 createGlobalStore 中显式声明类型,VS Code 等编辑器通常也能自动推断出正确的类型。

配合 ahooks 使用(可以是其他任意的 hook 库)

能够无痛复用各种 hooks 并将之于 store 整合在一起就是我认为 hox + ahooks 比 zustand + tanstack-query 要好的理由。 zustand 就没有这种类似的自由组合自定义 hook 的能力,相信我,在 zustand 里面实现请求的节流、防抖、轮询等逻辑就是噩梦,把请求放在 tanstack-query 这种不伦不类的用法真看不懂。

ahooks 是阿里巴巴开源的高质量 React Hooks 库,它提供了丰富的工具 Hook,能够与 Hox 形成完美的互补。ahooks 的特点是大而全、文档详细、质量可靠,已被大量国内外企业采用。

Hox 的一个重要优势是:你可以在全局状态模型中自由使用任何 React Hooks,包括 ahooks。这意味着你可以把 ahooks 的能力直接封装进全局状态,让状态管理模型更加强大。

useRequest:在 Hox 模型中管理网络请求

useRequest 是 ahooks 最核心的 Hook 之一,专门用于管理网络请求的状态。将 useRequest 融入 Hox 模型,可以轻松实现数据获取、轮询、缓存、防抖等功能:

// models/useUser.js
import { createGlobalStore } from 'hox'
import { useRequest } from 'ahooks'

export default createGlobalStore(function useUser() {
  const { data, loading, error, run, refresh, mutate } = useRequest(
    (userId) => fetch(`/api/users/${userId}`).then(res => res.json()),
    {
      manual: false,
      defaultParams: [1],
    }
  )

  const updateUser = async (userId, updates) => {
    const originalData = data.value
  
    mutate((currentData) => ({
      ...currentData,
      ...updates
    }))

    try {
      await fetch(`/api/users/${userId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updates)
      })
      refresh()
    } catch (err) {
      mutate(() => originalData)
    }
  }

  return {
    user: data,
    loading,
    error,
    refresh,
    updateUser,
  }
})

这样一来,使用该状态的组件只需要调用 useUser() 即可自动获得请求状态,无需在每个组件中重复编写请求逻辑。

useRequest 的配置项非常丰富:pollingInterval 可以设置轮询间隔,实现定时刷新;debounceInterval 可以将请求防抖处理,避免频繁请求;refreshOnWindowFocus 可以在窗口重新获得焦点时自动刷新数据;cacheKey 和 cacheTime 则提供了数据缓存能力。

useDebounce:在 Hox 模型中处理防抖

对于需要防抖或节流的场景,可以在 Hox 模型中直接使用 ahooks:

// models/useSearch.js
import { createGlobalStore } from 'hox'
import { useState, useEffect } from 'react'
import { useDebounce } from 'ahooks'

export default createGlobalStore(function useSearch() {
  const [keyword, setKeyword] = useState('')
  const [results, setResults] = useState([])
  const debouncedKeyword = useDebounce(keyword, { wait: 500 })

  useEffect(() => {
    if (!debouncedKeyword) {
      setResults([])
      return
    }
  
    fetch(`/api/search?q=${debouncedKeyword}`)
      .then(res => res.json())
      .then(data => setResults(data))
  }, [debouncedKeyword])

  return {
    keyword,
    setKeyword,
    results,
  }
})

useLocalStorageState:在 Hox 模型中持久化状态

如果需要将状态持久化到 localStorage,useLocalStorageState 提供了优雅的解决方案:

// models/useSettings.js
import { createGlobalStore } from 'hox'
import { useLocalStorageState } from 'ahooks'

export default createGlobalStore(function useSettings() {
  const [theme, setTheme] = useLocalStorageState('app-theme', 'light')
  const [language, setLanguage] = useLocalStorageState('app-language', 'zh-CN')

  const toggleTheme = () => {
    setTheme(t => t === 'light' ? 'dark' : 'light')
  }

  return {
    theme,
    language,
    setTheme,
    setLanguage,
    toggleTheme,
  }
})

这个 Hook 会自动处理序列化、反序列化,以及跨标签页同步等细节。组件中使用时:

import useSettings from '../models/useSettings'

function ThemeToggle() {
  const { theme, toggleTheme } = useSettings()
  
  return (
    <button onClick={toggleTheme}>
      当前主题: {theme}
    </button>
  )
}

这些 Hook 大多数都是独立的,可以直接与 Hox 或其他状态管理方案配合使用。ahooks 的设计理念是“即插即用”,你不需要为了使用某个 Hook 而引入整个库,可以按需导入。

适用场景

任何技术方案都有其适用范围,Hox + ahooks 也不例外。理解这些方案的适用场景,能够帮助我们做出更明智的技术决策。

Hox + ahooks 最适合以下场景:首先是中小型项目,这类项目通常不需要复杂的状态架构,但仍然需要状态共享能力;其次是追求开发效率的团队,Hox 的学习曲线几乎为零,开发者可以立即投入生产;第三是对代码简洁性有要求的项目,Hox + ahooks 的组合代码量极小,可读性好;第四是需要快速迭代的项目,由于 Hox 的零心智负担特性,重构和调整都变得轻而易举;最后是个人项目或初创项目,这类场景通常追求快速上线而非长期可维护性。

对于大型企业级项目,Redux Toolkit 仍然是更稳妥的选择。Redux 的严格约束在大型团队中能够发挥优势:统一的状态结构使得代码审查更容易,强大的调试工具能够快速定位问题,完善的中间件生态能够满足各类扩展需求。虽然 Redux 的学习曲线较陡,但一旦团队掌握,往往能够保持较高的一致性。

总结

状态管理是 React 开发中的核心议题,选择合适的方案对项目成功至关重要。本文详细介绍了当前主流的状态管理方案:Redux Toolkit 适合大型项目和对规范性有高要求的团队;Zustand + tanstack-query 则是中型项目的热门选择,兼顾了简洁性和功能性;而 Hox + ahooks 的组合,以其极简的设计理念和零学习成本,成为中小型项目的理想选择。

Hox 的核心优势可以概括为三点:首先是简单,它使用与普通 Hook 完全一致的 API,不需要额外的概念;其次是直观,状态管理逻辑与组件逻辑写在同样的位置,代码可读性极高;第三是灵活,它既支持简单的全局状态,也能处理复杂的异步逻辑和副作用。

在实际项目中,我建议采用渐进式的技术选型策略:从小处着手,先使用本地状态和 Context 来解决简单需求;当发现状态开始变得难以管理时,再引入 Hox 来抽象全局状态;遇到复杂的网络请求场景时,补充 ahooks 的 useRequest。这种方式能够避免过早引入复杂性,让项目保持轻盈的同时具备扩展能力。

最后,技术的选择永远应该服务于业务需求。没有最好的方案,只有最适合的方案。希望本文能够帮助你更好地理解 React 状态管理的生态,并在实际项目中做出明智的技术决策。

❌
❌