每个 React 开发者都需要的 10 个浏览器 API Hooks

18 阅读3分钟

学习如何在 React 中使用 Geolocation、Clipboard、Fullscreen、Media Queries 等浏览器 API,借助 ReactUse 提供的简洁、可复用的 Hooks。

原文发布于 reactuse.com

现代浏览器提供了强大的 API,包括地理定位、剪贴板访问、全屏模式、网络状态等等。在 React 中直接使用它们比应有的难度更大。你需要防范服务端渲染、添加和移除事件监听器、处理权限,以及在卸载时清理。将这些工作乘以你的应用涉及的每个浏览器 API,你就有了大量重复且容易出错的代码。

ReactUse 通过一个包含 100 多个 Hooks 的库来解决这个问题,将浏览器 API 封装为简洁的、SSR 安全的、TypeScript 友好的接口。只需安装一次,按需导入:

npm i @reactuses/core

1. useMediaQuery -- 响应式设计

在 JavaScript 中响应 CSS 媒体查询。该 Hook 返回一个布尔值,在视口变化时实时更新。

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 要求和焦点状态边界情况。

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 监听器。

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,返回当前状态和控制函数。

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 追踪在线/离线状态,在可用时还提供连接详情。

import { useNetwork } from "@reactuses/core";

function NetworkBanner() {
  const { online, effectiveType } = useNetwork();
  if (!online) return <div className="banner">您已离线</div>;
  return <div>连接类型: {effectiveType}</div>;
}

6. useIdle -- 空闲检测

检测用户何时停止与页面交互。

import { useIdle } from "@reactuses/core";

function IdleWarning() {
  const isIdle = useIdle(300_000); // 5 分钟
  return isIdle ? <div>你还在吗?</div> : null;
}

7. useDarkMode -- 深色模式切换

管理深色模式,包含系统偏好检测、localStorage 持久化和根元素自动类名切换。

import { useDarkMode } from "@reactuses/core";

function ThemeToggle() {
  const [isDark, toggle] = useDarkMode({
    classNameDark: "dark",
    classNameLight: "light",
  });
  return (
    <button onClick={toggle}>
      {isDark ? "切换到浅色" : "切换到深色"}
    </button>
  );
}

8. usePermission -- 权限状态

查询浏览器权限的状态并实时响应变化。

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 安全性、跨标签页同步和错误恢复。

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 安全的事件类型。

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。查看全部 →