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应用程序。