所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

React Hooks 数据请求库——SWR使用详解

简介

SWR(stale-while-revalidate)是由 Vercel 团队推出的 React Hooks 数据请求库,专注于高效的数据获取、缓存和自动更新。它基于 HTTP 缓存的“陈旧-再验证”策略,能够让页面始终显示最新的数据,同时保证极致的性能和用户体验。

SWR 的核心优势包括:

  • 自动缓存和请求去重:相同请求只会发送一次,数据自动缓存,避免重复请求。
  • 实时数据更新:支持自动轮询、焦点重新获取、网络恢复自动刷新等机制,保证数据新鲜。
  • 灵活的错误重试和加载状态管理:内置错误重试、加载指示等,开发体验极佳。
  • 与后端无关:支持 RESTful、GraphQL、数据库等多种数据源,fetcher 可自定义。

安装 SWR

npm install swr

基本用法

SWR 的核心是 useSWR Hook。最简单的用法如下:

import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function SwrDemo() {
  const { data, error, isLoading, mutate } = useSWR(
    "https://api.github.com/users/octocat",
    fetcher
  );

  if (isLoading) return <div className="container">加载中...</div>;
  if (error) return <div className="container">加载失败: {error.message}</div>;

  return (
    <div className="container" style={{ padding: 24 }}>
      <h2>GitHub 用户信息(octocat)</h2>
      <img
        src={data.avatar_url}
        alt="avatar"
        width={80}
        style={{ borderRadius: 8 }}
      />
      <p>
        <strong>用户名:</strong> {data.login}
      </p>
      <p>
        <strong>简介:</strong> {data.bio}
      </p>
      <p>
        <strong>主页:</strong>{" "}
        <a href={data.html_url} target="_blank" rel="noopener noreferrer">
          {data.html_url}
        </a>
      </p>
      <button onClick={() => mutate()}>刷新</button>
    </div>
  );
}

手动触发请求(mutate)

有时候你需要手动刷新数据,比如用户更新后:

import React from "react";
import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function SwrDemo() {
  // 固定 key,不自动请求
  const { data, error, isLoading, mutate } = useSWR("octocat", {
    fetcher: () => {}, // 默认不请求
    revalidateOnMount: false, // 挂载时不自动请求
  });

  // 手动触发 mutate
  const handleFetch = async () => {
    await mutate(() => fetcher("https://api.github.com/users/octocat"), {
      revalidate: false,
    });
  };

  return (
    <div className="container" style={{ padding: 24 }}>
      <h2>SWR mutate 手动触发请求示例</h2>
      <button
        onClick={handleFetch}
        disabled={isLoading}
        style={{
          padding: "8px 16px",
          marginBottom: 16,
          backgroundColor: isLoading ? "#ccc" : "#1890ff",
          color: "white",
          border: "none",
          borderRadius: 4,
          cursor: isLoading ? "not-allowed" : "pointer",
        }}
      >
        {isLoading ? "请求中..." : "手动获取 GitHub 用户信息"}
      </button>

      {error && (
        <div style={{ color: "red", marginBottom: 16 }}>
          请求失败: {error.message}
        </div>
      )}

      {data && (
        <div
          style={{
            padding: 16,
            border: "1px solid #d9d9d9",
            borderRadius: 4,
            backgroundColor: "#fafafa",
          }}
        >
          <h3>用户信息</h3>
          <img
            src={data.avatar_url}
            alt="avatar"
            width={80}
            style={{ borderRadius: 8, marginBottom: 8 }}
          />
          <p>
            <strong>用户名:</strong> {data.login}
          </p>
          <p>
            <strong>简介:</strong> {data.bio || "暂无简介"}
          </p>
          <p>
            <strong>主页:</strong>{" "}
            <a href={data.html_url} target="_blank" rel="noopener noreferrer">
              {data.html_url}
            </a>
          </p>
        </div>
      )}
    </div>
  );
}

自动重新请求

import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function Demo() {
  const { data, error, isLoading } = useSWR(
    "https://api.github.com/users/octocat",
    fetcher,
    {
      refreshInterval: 3000, // 每3秒自动重新请求一次
      revalidateOnFocus: false, // 切换标签页时不自动请求
    }
  );

  return (
    <div className="container" style={{ padding: 24 }}>
      <h2>SWR 自动重新请求(轮询)示例</h2>
      <p style={{ color: "#888", fontSize: 12 }}>每3秒自动刷新一次数据</p>
      {isLoading && <div>加载中...</div>}
      {error && <div style={{ color: "red" }}>请求失败: {error.message}</div>}
      {data && (
        <div
          style={{
            padding: 16,
            border: "1px solid #d9d9d9",
            borderRadius: 4,
            background: "#fafafa",
          }}
        >
          <h3>用户信息</h3>
          <img
            src={data.avatar_url}
            alt="avatar"
            width={80}
            style={{ borderRadius: 8, marginBottom: 8 }}
          />
          <p>
            <strong>用户名:</strong> {data.login}
          </p>
          <p>
            <strong>简介:</strong> {data.bio || "暂无简介"}
          </p>
          <p>
            <strong>主页:</strong>{" "}
            <a href={data.html_url} target="_blank" rel="noopener noreferrer">
              {data.html_url}
            </a>
          </p>
        </div>
      )}
    </div>
  );
}

分页 useSWRInfinite

import React from "react";
import useSWRInfinite from "swr/infinite";

const fetcher = (url) => fetch(url).then((res) => res.json());

// 获取每一页的 key
const getKey = (pageIndex, previousPageData) => {
  // 没有更多数据时
  if (previousPageData && previousPageData.length === 0) return null;
  // GitHub 用户分页API(每页5个)
  return `https://api.github.com/users?since=${pageIndex * 5}&per_page=5`;
};

export default function Demo() {
  const { data, error, isLoading, size, setSize, isValidating } =
    useSWRInfinite(getKey, fetcher);

  // 合并所有页的数据
  const users = data ? [].concat(...data) : [];
  const isEmpty = data?.[0]?.length === 0;
  const isReachingEnd = isEmpty || (data && data[data.length - 1]?.length < 5);

  return (
    <div className="container" style={{ padding: 24 }}>
      <h2>SWR useSWRInfinite 分页示例</h2>
      <p style={{ color: "#888", fontSize: 12 }}>每页5个用户,点击加载更多</p>
      {isLoading && <div>加载中...</div>}
      {error && <div style={{ color: "red" }}>请求失败: {error.message}</div>}
      <ul style={{ padding: 0, listStyle: "none" }}>
        {users.map((user) => (
          <li
            key={user.id}
            style={{ display: "flex", alignItems: "center", marginBottom: 12 }}
          >
            <img
              src={user.avatar_url}
              alt={user.login}
              width={36}
              style={{ borderRadius: 18, marginRight: 12 }}
            />
            <a href={user.html_url} target="_blank" rel="noopener noreferrer">
              {user.login}
            </a>
          </li>
        ))}
      </ul>
      <button
        onClick={() => setSize(size + 1)}
        disabled={isLoading || isValidating || isReachingEnd}
        style={{
          padding: "8px 16px",
          backgroundColor:
            isLoading || isValidating || isReachingEnd ? "#ccc" : "#1890ff",
          color: "white",
          border: "none",
          borderRadius: 4,
          cursor:
            isLoading || isValidating || isReachingEnd
              ? "not-allowed"
              : "pointer",
        }}
      >
        {isReachingEnd ? "没有更多了" : isValidating ? "加载中..." : "加载更多"}
      </button>
    </div>
  );
}

配置选项

SWR 支持很多配置,比如自动刷新、错误重试等:

const { data, error } = useSWR("/api/user", fetcher, {
  refreshInterval: 5000, // 每 5 秒自动刷新
  revalidateOnFocus: true, // 页面聚焦时自动刷新
  shouldRetryOnError: false, // 出错时不自动重试
});

更多配置参数

配置项类型默认值说明
refreshIntervalnumber0自动刷新间隔(毫秒),0 表示不自动刷新
revalidateOnFocusbooleantrue页面聚焦时自动重新请求
shouldRetryOnErrorbooleantrue请求出错时是否自动重试
dedupingIntervalnumber2000去重请求的时间间隔(毫秒)
errorRetryCountnumber5出错时重试的最大次数
errorRetryIntervalnumber5000出错重试的时间间隔(毫秒)
fallbackDataanyundefined初始数据,未请求到数据时使用
suspensebooleanfalse是否启用 React Suspense
onSuccessfunction请求成功时的回调
onErrorfunction请求失败时的回调

与数据库的关系

SWR 只是前端数据请求和缓存工具,实际数据库操作由后端 API 完成。SWR 负责高效请求、缓存和自动刷新,提升用户体验。


总结

  • SWR 适合前端高效请求和缓存数据
  • 支持自动刷新、错误重试、手动刷新等高级用法
  • 结合后端 API,可实现与数据库的数据交互

如需更复杂的用法(如分页、依赖请求等),可查阅 SWR 官方文档:https://swr.vercel.app/zh-CN

资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/795,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?