学习如何在 React 中使用 Geolocation、Clipboard、Fullscreen、Media Queries 等浏览器 API,借助 ReactUse 提供的简洁、可复用的 Hooks。
原文发布于 reactuse.com
现代浏览器提供了强大的 API,包括地理定位、剪贴板访问、全屏模式、网络状态等等。在 React 中直接使用它们比应有的难度更大。你需要防范服务端渲染、添加和移除事件监听器、处理权限,以及在卸载时清理。将这些工作乘以你的应用涉及的每个浏览器 API,你就有了大量重复且容易出错的代码。
ReactUse 通过一个包含 100 多个 Hooks 的库来解决这个问题,将浏览器 API 封装为简洁的、SSR 安全的、TypeScript 友好的接口。只需安装一次,按需导入:
bash
npm i @reactuses/core
1. useMediaQuery -- 响应式设计
在 JavaScript 中响应 CSS 媒体查询。该 Hook 返回一个布尔值,在视口变化时实时更新。
tsx
import { useMediaQuery } from "@reactuses/core";
function App() {
const isMobile = useMediaQuery("(max-width: 768px)");
return <div>{isMobile ? <MobileNav /> : <DesktopNav />}</div>;
}
2. useClipboard -- 复制到剪贴板
使用现代 Clipboard API 读写系统剪贴板。该 Hook 处理权限、HTTPS 要求和焦点状态边界情况。
tsx
import { useClipboard } from "@reactuses/core";
function CopyButton({ text }: { text: string }) {
const [clipboardText, copy] = useClipboard();
return (
<button onClick={() => copy(text)}>
{clipboardText === text ? "Copied!" : "Copy"}
</button>
);
}
3. useGeolocation -- 用户位置
追踪用户的地理坐标,在卸载时自动清理 watchPosition 监听器。
tsx
import { useGeolocation } from "@reactuses/core";
function LocationDisplay() {
const { coordinates, error, isSupported } = useGeolocation();
if (!isSupported) return <p>不支持地理定位。</p>;
if (error) return <p>错误: {error.message}</p>;
return <p>纬度: {coordinates.latitude}, 经度: {coordinates.longitude}</p>;
}
4. useFullscreen -- 全屏模式
对任意元素切换全屏。该 Hook 封装了 Fullscreen API,返回当前状态和控制函数。
tsx
import { useRef } from "react";
import { useFullscreen } from "@reactuses/core";
function VideoPlayer() {
const ref = useRef<HTMLDivElement>(null);
const [isFullscreen, { toggleFullscreen }] = useFullscreen(ref);
return (
<div ref={ref}>
<video src="/demo.mp4" />
<button onClick={toggleFullscreen}>
{isFullscreen ? "退出" : "全屏"}
</button>
</div>
);
}
5. useNetwork -- 在线/离线状态
监控用户的网络连接。该 Hook 追踪在线/离线状态,在可用时还提供连接详情。
tsx
import { useNetwork } from "@reactuses/core";
function NetworkBanner() {
const { online, effectiveType } = useNetwork();
if (!online) return <div className="banner">您已离线</div>;
return <div>连接类型: {effectiveType}</div>;
}
6. useIdle -- 空闲检测
检测用户何时停止与页面交互。
tsx
import { useIdle } from "@reactuses/core";
function IdleWarning() {
const isIdle = useIdle(300_000); // 5 分钟
return isIdle ? <div>你还在吗?</div> : null;
}
7. useDarkMode -- 深色模式切换
管理深色模式,包含系统偏好检测、localStorage 持久化和根元素自动类名切换。
tsx
import { useDarkMode } from "@reactuses/core";
function ThemeToggle() {
const [isDark, toggle] = useDarkMode({
classNameDark: "dark",
classNameLight: "light",
});
return (
<button onClick={toggle}>
{isDark ? "切换到浅色" : "切换到深色"}
</button>
);
}
8. usePermission -- 权限状态
查询浏览器权限的状态并实时响应变化。
tsx
import { usePermission } from "@reactuses/core";
function CameraAccess() {
const status = usePermission("camera");
if (status === "denied") return <p>摄像头访问被拒绝。</p>;
if (status === "prompt") return <p>我们需要摄像头权限。</p>;
return <p>摄像头访问已授权。</p>;
}
9. useLocalStorage -- 持久化状态
useState 的替代方案,持久化到 localStorage。处理序列化、SSR 安全性、跨标签页同步和错误恢复。
tsx
import { useLocalStorage } from "@reactuses/core";
function Settings() {
const [lang, setLang] = useLocalStorage("language", "en");
return (
<select value={lang ?? "en"} onChange={(e) => setLang(e.target.value)}>
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
</select>
);
}
10. useEventListener -- 事件处理
将事件监听器附加到任何目标,自动清理,并提供 TypeScript 安全的事件类型。
tsx
import { useEventListener } from "@reactuses/core";
function KeyLogger() {
useEventListener("keydown", (event) => {
console.log("按键:", event.key);
});
return <p>按任意键...</p>;
}
手动实现 vs. ReactUse
| 关注点 | 手动实现 | ReactUse Hook |
|---|---|---|
| SSR 安全检查 | 到处添加 typeof window !== "undefined" |
内置 |
| 事件监听器清理 | useEffect + removeEventListener |
自动 |
| TypeScript 事件类型 | 手动泛型约束 | 完全类型化 |
| localStorage 序列化 | JSON.parse/stringify + 错误处理 |
自动 |
| 跨标签页同步 | 手动 storage 事件监听 |
内置 |
对于单个 Hook 来说节省量不大。但在整个应用中使用五个或更多浏览器 API 时,ReactUse 消除了数百行防御性代码。
ReactUse 提供了 100 多个 React Hooks。查看全部 →