跳转到内容

Next.js SWR钩子

来自代码酷

Next.js SWR钩子[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

SWR(Stale-While-Revalidate)是Next.js中一个强大的数据获取钩子,由Vercel团队开发。它基于HTTP缓存策略"Stale-While-Revalidate",允许应用程序在后台重新验证数据的同时立即显示缓存(可能过时)的数据。SWR特别适合需要实时数据更新的应用程序,同时保持优秀的用户体验。

SWR的主要特点包括:

  • 轻量级且易于使用
  • 内置缓存和请求去重
  • 自动重新验证数据
  • 支持TypeScript
  • 可定制的重新验证策略

基本用法[编辑 | 编辑源代码]

要使用SWR,首先需要安装它:

npm install swr
# 或
yarn add swr

然后可以在组件中这样使用:

import useSWR from 'swr'

function Profile() {
  const { data, error, isLoading } = useSWR('/api/user', fetcher)

  if (error) return <div>加载失败</div>
  if (isLoading) return <div>加载中...</div>
  
  return <div>你好, {data.name}!</div>
}

这里:

  • /api/user - 数据请求的key(通常是API端点)
  • fetcher - 一个函数,接收key并返回数据
  • data - 获取的数据
  • error - 错误对象
  • isLoading - 加载状态

创建fetcher函数[编辑 | 编辑源代码]

fetcher是一个简单的异步函数,通常使用fetch或axios:

const fetcher = (...args) => fetch(...args).then(res => res.json())

或者使用axios:

import axios from 'axios'

const fetcher = url => axios.get(url).then(res => res.data)

高级特性[编辑 | 编辑源代码]

自动重新验证[编辑 | 编辑源代码]

SWR会自动在以下情况下重新验证数据:

  • 当窗口重新获得焦点时
  • 当网络重新连接时
  • 可以配置定时重新验证

条件获取[编辑 | 编辑源代码]

可以基于条件禁用数据获取:

const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)

依赖请求[编辑 | 编辑源代码]

可以创建依赖其他SWR请求的请求:

function MyProjects() {
  const { data: user } = useSWR('/api/user')
  const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
  
  if (!projects) return '加载中...'
  return '你有' + projects.length + '个项目'
}

全局配置[编辑 | 编辑源代码]

可以使用SWRConfig提供全局配置:

import { SWRConfig } from 'swr'

function App() {
  return (
    <SWRConfig 
      value={{
        refreshInterval: 3000,
        fetcher: (resource, init) => fetch(resource, init).then(res => res.json())
      }}
    >
      <Profile />
    </SWRConfig>
  )
}

实际应用案例[编辑 | 编辑源代码]

实时仪表盘[编辑 | 编辑源代码]

假设我们正在构建一个实时监控仪表盘:

function Dashboard() {
  const { data: stats, error } = useSWR('/api/stats', fetcher, {
    refreshInterval: 5000 // 每5秒刷新一次
  })

  if (error) return <ErrorAlert />
  if (!stats) return <LoadingSpinner />
  
  return (
    <div>
      <h1>系统状态</h1>
      <div>当前用户: {stats.users}</div>
      <div>活跃会话: {stats.sessions}</div>
      <div>服务器负载: {stats.load}%</div>
    </div>
  )
}

分页数据[编辑 | 编辑源代码]

SWR可以很好地处理分页:

function Posts({ pageIndex }) {
  const { data: posts } = useSWR(`/api/posts?page=${pageIndex}`, fetcher)
  
  return (
    <ul>
      {posts?.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

性能优化[编辑 | 编辑源代码]

预加载数据[编辑 | 编辑源代码]

可以在页面导航前预加载数据:

import { mutate } from 'swr'

function Link({ href }) {
  return (
    <a
      href={href}
      onMouseEnter={() => mutate(href, fetch(href).then(res => res.json()))}
    >
      链接
    </a>
  )
}

乐观更新[编辑 | 编辑源代码]

SWR支持乐观UI更新:

function LikeButton({ id }) {
  const { data, mutate } = useSWR(`/api/post/${id}`, fetcher)
  
  const handleLike = async () => {
    const newLikes = (data.likes || 0) + 1
    
    // 乐观更新UI
    mutate({ ...data, likes: newLikes }, false)
    
    // 发送请求到API
    await fetch(`/api/post/${id}/like`, { method: 'POST' })
    
    // 重新验证确保数据正确
    mutate()
  }
  
  return <button onClick={handleLike}>点赞 ({data?.likes || 0})</button>
}

错误处理[编辑 | 编辑源代码]

SWR提供了多种错误处理方式:

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher, {
    onErrorRetry: (error, key, config, revalidate, { retryCount }) => {
      // 404错误时不重试
      if (error.status === 404) return
      
      // 最多重试10次
      if (retryCount >= 10) return
      
      // 5秒后重试
      setTimeout(() => revalidate({ retryCount: retryCount + 1 }), 5000)
    }
  })
  
  if (error) {
    if (error.status === 404) {
      return <div>用户不存在</div>
    }
    return <div>加载失败</div>
  }
  
  if (!data) return <div>加载中...</div>
  
  return <div>你好, {data.name}!</div>
}

与Next.js集成的最佳实践[编辑 | 编辑源代码]

预取数据[编辑 | 编辑源代码]

在Next.js中,可以结合getStaticProps或getServerSideProps预取数据:

export async function getStaticProps() {
  const user = await fetcher('/api/user')
  return { props: { fallback: { '/api/user': user } } }
}

function Profile({ fallback }) {
  return (
    <SWRConfig value={{ fallback }}>
      <UserProfile />
    </SWRConfig>
  )
}

无限加载[编辑 | 编辑源代码]

结合useSWRInfinite实现无限加载:

import useSWRInfinite from 'swr/infinite'

const getKey = (pageIndex, previousPageData) => {
  if (previousPageData && !previousPageData.length) return null // 到达末尾
  return `/api/items?page=${pageIndex}&limit=10` // SWR key
}

function Items() {
  const { data, size, setSize } = useSWRInfinite(getKey, fetcher)
  
  if (!data) return <div>加载中...</div>
  
  const items = data.flat()
  
  return (
    <>
      <ul>
        {items.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
      <button onClick={() => setSize(size + 1)}>加载更多</button>
    </>
  )
}

常见问题[编辑 | 编辑源代码]

为什么选择SWR而不是直接使用fetch或axios?[编辑 | 编辑源代码]

SWR提供了:

  • 自动缓存
  • 自动重新验证
  • 请求去重
  • 更简单的错误处理
  • 更优雅的加载状态管理

SWR适合所有数据获取场景吗?[编辑 | 编辑源代码]

虽然SWR非常强大,但在以下情况下可能需要考虑其他方案:

  • 需要完全控制请求生命周期
  • 需要处理非常复杂的请求链
  • 需要与特定的状态管理库深度集成

总结[编辑 | 编辑源代码]

SWR是Next.js应用中数据获取的强大工具,它简化了客户端数据管理,提供了优秀的用户体验和开发者体验。通过智能缓存、自动重新验证和丰富的配置选项,SWR可以帮助开发者构建高效、响应迅速的现代Web应用程序。