NextJS之SWR

半兽人 发表于: 2025-04-02   最后更新时间: 2025-04-02 14:55:43  
{{totalSubscript}} 订阅, 26 游览

SWR 是什么?

SWR 是一个由 Vercel(Next.js 开发公司)推出的 React 数据获取库,用于高效获取、缓存和自动同步远程数据。

SWR 代表:

  • Stale(过期)
  • While(在)
  • Revalidate(重新验证)

SWR 的核心思想是:

先返回缓存数据(如果有),然后发送请求获取最新数据,并自动更新 UI。

SWR 适用于:

  • 数据请求和缓存管理(Client-Side Fetching)
  • 自动重新验证数据(如窗口聚焦、重新连接)
  • SSR & ISR 支持(与 Next.js 兼容)

SWR 的主要功能

  1. 自动缓存和重新验证(避免重复请求)
  2. 支持窗口聚焦时自动刷新数据
  3. 支持离线恢复(重新连接后自动同步)
  4. 支持数据依赖(可基于一个请求的结果触发另一个请求)
  5. 支持乐观 UI 更新(Optimistic UI)

如何使用 SWR?

1. 安装 SWR

npm install swr

2. 在 React 组件中使用 SWR

import useSWR from 'swr'

// 定义请求方法
const fetcher = (url: string) => fetch(url).then(res => res.json())

export default function Profile() {
  // SWR 请求数据
  const { data, error, isLoading } = useSWR('/api/user', fetcher)

  if (error) return <div>获取数据失败</div>
  if (isLoading) return <div>加载中...</div>

  return <div>用户名称: {data.name}</div>
}

解释:

  • useSWR('/api/user', fetcher):向 /api/user 发送 GET 请求,并返回数据
  • data:存储服务器返回的数据
  • error:存储请求失败的错误信息
  • isLoading:指示是否仍在加载数据

SWR 的高级用法

1. 全局配置 SWR

可以使用 SWRConfig 提供全局配置,比如全局 fetcher、刷新策略等:

import { SWRConfig } from 'swr'

export default function MyApp({ Component, pageProps }) {
  return (
    <SWRConfig value={{ fetcher: (url) => fetch(url).then(res => res.json()) }}>
      <Component {...pageProps} />
    </SWRConfig>
  )
}

这样,所有 useSWR() 的请求都会自动使用这个 fetcher

明确对比 全局配置 vs. 局部配置的区别。

例子 1:没有 <SWRConfig>,每个请求都要手动写参数

如果没有 <SWRConfig>,我们必须在每个 useSWR() 里单独写 shouldRetryOnError: falserevalidateOnFocus: false

import useSWR from 'swr'

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

function UserProfile() {
  const { data, error } = useSWR('/api/user', fetcher, {
    shouldRetryOnError: false,
    revalidateOnFocus: false
  })

  if (error) return <div>加载失败</div>
  if (!data) return <div>加载中...</div>

  return <div>用户名: {data.name}</div>
}

function UserPosts() {
  const { data, error } = useSWR('/api/posts', fetcher, {
    shouldRetryOnError: false,
    revalidateOnFocus: false
  })

  if (error) return <div>加载失败</div>
  if (!data) return <div>加载中...</div>

  return (
    <ul>
      {data.map(post => <li key={post.id}>{post.title}</li>)}
    </ul>
  )
}

export default function App() {
  return (
    <div>
      <UserProfile />
      <UserPosts />
    </div>
  )
}

缺点

  • shouldRetryOnError: falserevalidateOnFocus: false 在每个请求中都要重复写,代码冗余,维护麻烦。

例子 2:使用 <SWRConfig> 统一管理

使用 <SWRConfig>,所有 useSWR() 自动继承默认配置

import { SWRConfig } from 'swr'
import useSWR from 'swr'

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

function UserProfile() {
  const { data, error } = useSWR('/api/user')

  if (error) return <div>加载失败</div>
  if (!data) return <div>加载中...</div>

  return <div>用户名: {data.name}</div>
}

function UserPosts() {
  const { data, error } = useSWR('/api/posts')

  if (error) return <div>加载失败</div>
  if (!data) return <div>加载中...</div>

  return (
    <ul>
      {data.map(post => <li key={post.id}>{post.title}</li>)}
    </ul>
  )
}

export default function App() {
  return (
    <SWRConfig value={{
      fetcher,                // 全局 fetcher
      shouldRetryOnError: false,
      revalidateOnFocus: false
    }}>
      <UserProfile />
      <UserPosts />
    </SWRConfig>
  )
}

优势

  1. UserProfileUserPosts 不用再手动传 shouldRetryOnErrorrevalidateOnFocus,代码更简洁。
  2. 统一管理 SWR 配置,方便维护

2. 依赖另一个数据

当一个 API 请求需要依赖另一个 API 的结果时:

function UserProfile() {
  const { data: user } = useSWR('/api/user', fetcher)
  const { data: projects } = useSWR(user ? `/api/projects?user=${user.id}` : null, fetcher)

  if (!user) return <div>加载用户信息...</div>
  if (!projects) return <div>加载项目列表...</div>

  return (
    <div>
      <h1>{user.name} 的项目</h1>
      <ul>
        {projects.map(p => (
          <li key={p.id}>{p.name}</li>
        ))}
      </ul>
    </div>
  )
}

关键点:

  • useSWR(user ? '/api/projects?user=' + user.id : null, fetcher)
    • 只有 user 数据加载完成后,才会发起 /api/projects 请求

3. 自动刷新数据

SWR 允许设置自动刷新时间,比如每隔 5 秒刷新一次:

const { data } = useSWR('/api/user', fetcher, { refreshInterval: 5000 })

4. 手动触发数据重新验证

import useSWR, { mutate } from 'swr'

const { data } = useSWR('/api/user', fetcher)

// 重新获取最新数据
const refreshData = () => {
  mutate('/api/user')
}

<button onClick={refreshData}>刷新用户数据</button>

mutate() 可以手动触发 SWR 重新获取数据,而无需用户刷新页面。


SWR vs React Query

特性 SWR React Query
提供缓存
自动重新验证
窗口聚焦刷新
手动触发更新 mutate() queryClient.invalidateQueries()
SSR/ISR 支持 ✅(适用于 Next.js) ✅(需要额外配置)
适用于简单数据请求
适用于复杂数据(分页、表单、请求依赖等) ⚠️(需要自定义)

选择建议:

  • SWR 适合 Next.js,用于简单数据获取(如用户信息、配置等)。
  • React Query 适合更复杂的应用,如分页、表单提交、乐观更新等。

总结

  • SWR 是一个 React 的数据获取库,基于“Stale-While-Revalidate”策略。
  • 提供高效的缓存、自动重新获取数据,支持窗口聚焦刷新等功能。
  • 适用于 Next.js 和客户端数据获取,提升用户体验。
更新于 2025-04-02

查看Next.js更多相关的文章或提一个关于Next.js的问题,也可以与我们一起分享文章