Shared
@skyroc/hooks
跨端 React hooks 集合,主入口 RN 安全,./web 子入口提供浏览器专用 hooks
概览
| 项 | 值 |
|---|---|
| 包名 | @skyroc/hooks |
| 目录 | packages/hooks |
| 版本 | 1.0.0 |
| 运行时依赖 | ahooks |
| peer | react >= 18.0.0 |
| 子入口 | .、./web |
| 测试 | ✅ 9 个 |
@skyroc/hooks 把项目中跨端复用的 React hooks 收拢成一个包。设计上严格区分**「RN 安全」与「Web 专用」**两个层级,避免 Native 端误打包浏览器 API。
子入口边界
| 入口 | 包含内容 | 适用平台 |
|---|---|---|
. | Store + 业务无关 hooks | Web / RN / MiniApp |
./web | 主入口全部 + 浏览器 DOM hooks | 仅浏览器 |
import { useCaptcha } from '@skyroc/hooks'; // ✅ 跨端
import { useCopy } from '@skyroc/hooks/web'; // ✅ 仅 WebHook 清单
主入口(.)
| Hook | 用途 |
|---|---|
useArray | 数组状态(push / pop / filter / clear 等便捷方法) |
useCaptcha | 验证码倒计时(含手机号校验、目标校验、自定义文案) |
useCountDownTimer | 通用倒计时器 |
useLoading | loading 状态(含 setLoading、withLoading(fn)) |
useNow | 实时时间(带可选刷新频率) |
useStore | 订阅 Store<S> 实例(基于 useSyncExternalStore) |
./web 额外
| Hook | 用途 |
|---|---|
useCopy | 调用剪贴板 API |
useSystemTheme | 监听 (prefers-color-scheme: dark) |
Store + useStore 模式
import { Store, useStore } from '@skyroc/hooks';
class CounterStore extends Store<{ count: number }> {
constructor() {
super({ count: 0 });
}
increment() {
this.setState({ count: this.state.count + 1 });
}
}
const counter = new CounterStore();
// 组件中
const { count } = useStore(counter);
counter.increment();设计思路:class 管理逻辑与状态,useStore 桥接到 React。相比 jotai 更面向 OOP,相比 Zustand 更轻量、可继承。详细使用见 packages/hooks/src/store/README.md。
useCaptcha 示例
const { count, label, start, isCounting, sendCaptcha } = useCaptcha({
duration: 60,
request: async phone => {
await fetchSendCode(phone);
},
validateTarget: phone => REG_PHONE.test(phone),
countingLabel: count => `${count}s 后重试`,
idleLabel: '发送验证码'
});
<Button disabled={isCounting} onClick={() => sendCaptcha(phone)}>
{label}
</Button>;ahooks 是内部实现
包没有 re-export ahooks 的 hook,而是封装特定 hook 形成更直接的 API。如果业务想用 ahooks 的其它 hook,直接 import { useXxx } from 'ahooks' 即可。
跨端策略
主入口(src/index.ts)的所有 hooks 都遵循「不依赖浏览器或 RN API」的原则:
useArray/useLoading/useStore纯 JSuseCaptcha/useCountDownTimer用setTimeoutuseNow用setInterval
需要 DOM 的 hooks 全部放 ./web:
useCopy用navigator.clipboarduseSystemTheme用window.matchMedia
// ❌ Native 端:会引入浏览器 API 报错
import { useCopy } from '@skyroc/hooks/web';
// ✅ Native 端:只用主入口
import { useArray, useLoading } from '@skyroc/hooks';./web 的 index.ts 还会 export * from '../index' re-export 主入口,所以 Web 端只 import './web' 一处即可。
目录结构
src/
├── index.ts # 主入口(RN 安全)
├── use-array.ts
├── use-captcha.ts
├── use-count-down-timer.ts
├── use-loading.ts
├── use-now.ts
├── store/
│ ├── store.ts # Store<S> 基类
│ ├── use-store.ts # useStore hook
│ └── README.md # store 详细文档
└── web/
├── index.ts # Web 子入口(含主入口 re-export)
├── use-copy.ts
└── use-system-theme.ts在项目中的消费
@skyroc/web-admin-layouts:使用useArray、useStore等@skyroc/web-admin-theme:使用useSystemTheme跟随系统暗色apps/admin/apps/admin-example:在登录页用useCaptcha
测试覆盖
9 个测试文件覆盖 Store、各 hook 与 web 子入口。Hook 测试用 @testing-library/react 的 renderHook。