详细的 React Hooks 与 Vue Composables 并排对比,探讨模式、性能,以及 ReactUse 如何将 VueUse 的最佳理念带到 React。
原文发布于 reactuse.com
React Hooks 是以 use 为前缀的函数,让 React 组件无需类即可管理状态、副作用和生命周期行为。Vue Composables 是利用 Vue 的 Composition API 来封装和复用组件间响应式逻辑的函数。两者解决的是同一个根本问题——共享有状态逻辑——但它们使用不同的响应式模型、执行语义和生态约定来实现。
为什么这个对比很重要
在 React 和 Vue 之间切换的开发者经常寻找等价的模式。Vue 生态有 VueUse,一个包含 200 多个 Composables 的集合,已成为可复用逻辑的黄金标准。寻求同样丰富实用 Hooks 的 React 开发者现在有了 ReactUse,一个包含 100 多个 Hooks 的库,直接受 VueUse 设计理念启发。
并排对比
| 方面 | React Hooks | Vue Composables |
|---|---|---|
| 响应式模型 | 状态变化时重新渲染整个组件 | 通过代理 ref 实现细粒度响应 |
| 执行方式 | 每次渲染都运行 | 在 setup() 中只运行一次 |
| 状态原语 | useState 返回值 + setter | ref() / reactive() 返回代理 |
| 副作用 | useEffect 带依赖数组 | watchEffect 自动追踪 |
| 生命周期 | useEffect 清理模式 | onMounted、onUnmounted 等 |
| 规则 | 必须遵循 Hooks 规则 | 无顺序约束 |
| SSR | 需要手动 typeof window 防护 | 内置 onServerPrefetch |
| 记忆化 | 显式(useMemo、useCallback) | 通过 computed() 自动 |
| 主流实用库 | ReactUse(100+ Hooks) | VueUse(200+ Composables) |
底层响应式的差异
React Hooks 在每次渲染时重新执行。当你调用 useState 时,React 将值存储在内部 fiber 中,每次组件函数运行时都重新返回。派生值需要 useMemo 和显式的依赖数组,遗漏依赖是常见的 Bug 来源。
Vue Composables 在 setup() 中只运行一次。Ref 和 reactive 对象是 JavaScript 代理,追踪哪些 effect 依赖它们。当 ref 变化时,只有读取它的特定 effect 会被重新触发——而非整个组件。
代码对比:useLocalStorage
React 使用 ReactUse:
import { useLocalStorage } from "@reactuses/core";
function Settings() {
const [theme, setTheme] = useLocalStorage("theme", "light");
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
当前: {theme}
</button>
);
}
Vue 使用 VueUse:
<script setup>
import { useLocalStorage } from "@vueuse/core";
const theme = useLocalStorage("theme", "light");
function toggle() {
theme.value = theme.value === "light" ? "dark" : "light";
}
</script>
<template>
<button @click="toggle">当前: {{ theme }}</button>
</template>
API 表面几乎完全相同。ReactUse 返回一个模仿 useState 的 [value, setter] 元组。VueUse 返回一个你直接修改的响应式 ref。
代码对比:useWindowSize
React 使用 ReactUse:
import { useWindowSize } from "@reactuses/core";
function Layout() {
const { width, height } = useWindowSize();
return <p>窗口: {width} x {height}</p>;
}
Vue 使用 VueUse:
<script setup>
import { useWindowSize } from "@vueuse/core";
const { width, height } = useWindowSize();
</script>
<template>
<p>窗口: {{ width }} x {{ height }}</p>
</template>
代码对比:useDark
React 使用 ReactUse:
import { useDarkMode } from "@reactuses/core";
function ThemeToggle() {
const [isDark, toggle] = useDarkMode({ classNameDark: "dark", classNameLight: "light" });
return <button onClick={toggle}>{isDark ? "浅色" : "深色"}</button>;
}
Vue 使用 VueUse:
<script setup>
import { useDark, useToggle } from "@vueuse/core";
const isDark = useDark();
const toggle = useToggle(isDark);
</script>
<template>
<button @click="toggle">{{ isDark ? '浅色' : '深色' }}</button>
</template>
关键差异
执行模型。 React Hooks 在每次渲染时运行,Hook 内的每个变量每次组件更新时都会被重新创建。Vue Composables 只运行一次,响应式通过代理处理。
依赖追踪。 React 要求你在数组中显式声明依赖。Vue 在运行时自动追踪依赖。手动依赖数组是 React 中频繁的 Bug 来源。
SSR 方式。 React 通常检查 typeof window !== "undefined"。Vue 提供了 onServerPrefetch 等生命周期钩子。ReactUse 和 VueUse 都在内部处理这些防护。
生态成熟度。 VueUse 自 2020 年以来提供超过 200 个 Composables。ReactUse 较新但增长迅速,拥有 100 多个 Hooks。
ReactUse vs VueUse:React 的等价方案
| 能力 | ReactUse | VueUse |
|---|---|---|
| Hook/Composable 数量 | 100+ | 200+ |
| TypeScript | 一等支持 | 一等支持 |
| Tree-shaking | 是 | 是 |
| SSR 安全 | 是 | 是 |
| 交互式文档 | 是 | 是 |
对于欣赏 VueUse 的广度和易用性的 React 开发者来说,ReactUse 是目前最接近的等价方案。
常见问题
我可以在 React 中使用 VueUse 吗?
不可以。VueUse 依赖于 Vue 的响应式系统,无法在 Vue 应用之外运行。但 ReactUse 为 React 提供了等价的 Hooks。
VueUse 的 React 等价方案是什么?
ReactUse(@reactuses/core)。使用 npm i @reactuses/core 安装。
如果你是一个 React 开发者,希望获得 VueUse 为 Vue 带来的那种广度和精致,ReactUse 正是为你而建。
npm i @reactuses/core