2026年3月17日
ReactUse vs usehooks-ts:该选哪个 React Hooks 库?
ReactUse(@reactuses/core)和 usehooks-ts 都是以 TypeScript 为先的 React Hooks 库,旨在减少组件中的样板代码。它们有着相似的理念——提供简洁、可复用的 Hooks 和出色的类型推断——但在覆盖范围、SSR 处理和浏览器 API 支持方面存在显著差异。
我们维护着 ReactUse,所以有自己的立场。但我们已尽力做到公平,承认 usehooks-ts 的优势。
概览对比
| 特性 | ReactUse | usehooks-ts |
|---|---|---|
| Hook 数量 | 100+ | ~30 |
| TypeScript 优先 | 是 | 是 |
| Tree-shaking | 是 | 是 |
| SSR 安全 | 是(内置 isBrowser 防护) | 各 Hook 不一 |
| 每个 Hook 体积 | 小 | 小 |
| 分类体系 | 浏览器、状态、元素、传感器、动画、副作用 | 通用 |
| 交互式演示 | 是 | 否(展示源码) |
| 浏览器 API Hooks | 地理定位、剪贴板、全屏、语音、通知等 | 有限 |
| DOM 观察者 Hooks | IntersectionObserver、ResizeObserver、MutationObserver | 仅 IntersectionObserver |
| 维护状态 | 活跃 | 活跃 |
代码对比:useLocalStorage
ReactUse:
import { useLocalStorage } from "@reactuses/core";
function Settings() {
const [theme, setTheme] = useLocalStorage("theme", "light");
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
当前: {theme}
</button>
);
}
usehooks-ts:
import { useLocalStorage } from "usehooks-ts";
function Settings() {
const [theme, setTheme] = useLocalStorage("theme", "light");
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
当前: {theme}
</button>
);
}
两者的 API 几乎完全相同,都返回模仿 useState 的 [value, setter] 元组。这是 usehooks-ts 最大的优点之一——API 简洁且熟悉。
代码对比:useMediaQuery
ReactUse:
import { useMediaQuery } from "@reactuses/core";
function ResponsiveLayout() {
const isMobile = useMediaQuery("(max-width: 768px)");
return <div>{isMobile ? "移动端" : "桌面端"}</div>;
}
usehooks-ts:
import { useMediaQuery } from "usehooks-ts";
function ResponsiveLayout() {
const isMobile = useMediaQuery("(max-width: 768px)");
return <div>{isMobile ? "移动端" : "桌面端"}</div>;
}
同样非常相似。两个库都返回布尔值。区别在 SSR 层——ReactUse 内部对 window.matchMedia 调用进行了防护,在服务端渲染时安全地返回 false,无需你做额外处理。
代码对比:useDebounce
ReactUse:
import { useDebounceFn } from "@reactuses/core";
function Search() {
const { run } = useDebounceFn((query: string) => {
fetch(`/api/search?q=${query}`);
}, 300);
return <input onChange={(e) => run(e.target.value)} />;
}
usehooks-ts:
import { useDebounceCallback } from "usehooks-ts";
function Search() {
const debouncedFetch = useDebounceCallback((query: string) => {
fetch(`/api/search?q=${query}`);
}, 300);
return <input onChange={(e) => debouncedFetch(e.target.value)} />;
}
两者都能很好地工作。ReactUse 还额外提供 useThrottleFn、useDebouncedValue 和 useThrottledValue,满足更细粒度的控制需求。
SSR 安全性
这是两个库之间最重要的实际差异。
ReactUse 在每个访问 window、document 或 navigator 的 Hook 中内部检查 isBrowser。你永远不需要自己编写 typeof window !== "undefined"。这意味着 ReactUse 的 Hooks 在 Next.js、Remix 和任何其他 SSR 框架中开箱即用。
usehooks-ts 的 SSR 处理不够一致。部分 Hook 做了浏览器 API 防护,部分没有。如果你在构建 SSR 应用,可能需要在 usehooks-ts 的 Hook 外层添加自己的防护或使用动态导入,这增加了复杂度。
何时选择 usehooks-ts
usehooks-ts 在以下场景是不错的选择:
- 你只需要少量常用 Hooks(localStorage、media query、debounce、click outside)
- 你的项目是纯客户端 SPA,没有 SSR 需求
- 你希望依赖体积尽可能小
- 你喜欢在文档中直接阅读源码——usehooks-ts 展示了每个实现
usehooks-ts 在它的领域做得很好。实现简洁、可读、易理解。对于只需少量工具的小项目,它完全合理。
何时选择 ReactUse
ReactUse 更适合以下场景:
- 你在构建可能现在或将来需要 SSR 的生产应用
- 你需要基础之外的浏览器 API Hooks(地理定位、剪贴板、全屏、语音识别、电池状态、通知)
- 你需要 DOM 观察者 Hooks(IntersectionObserver、ResizeObserver、MutationObserver、元素边界)
- 你需要动画工具(useRafFn、useTransition、useInterval、useTimeout)
- 你需要传感器 Hooks(useDeviceMotion、useDeviceOrientation、useMouse、useScroll)
- 你希望用一个库覆盖 100+ 个场景,而非拼凑多个包
迁移指南:从 usehooks-ts 迁移到 ReactUse
如果你已在使用 usehooks-ts 并想迁移,过程很简单,因为两个库都遵循 [value, setter] 约定。
第一步:安装 ReactUse
npm i @reactuses/core
第二步:更新导入
| usehooks-ts | ReactUse |
|---|---|
useLocalStorage | useLocalStorage |
useMediaQuery | useMediaQuery |
useDebounceCallback | useDebounceFn |
useIntersectionObserver | useIntersectionObserver |
useEventListener | useEventListener |
useOnClickOutside | useClickOutside |
useCopyToClipboard | useClipboard |
第三步:移除 SSR 防护代码 ——ReactUse 在内部处理,你可以删除为 usehooks-ts Hooks 添加的所有 typeof window 检查。
安装
npm i @reactuses/core
import { useLocalStorage, useMediaQuery, useClipboard } from "@reactuses/core";
每个 Hook 都在 reactuse.com 上提供了在线演示、完整 API 参考和 TypeScript 定义。
今天就试试 ReactUse 吧。立即开始 →