使用 SWR,组件将会不断地、自动获得最新数据流。
UI 也会一直保持快速响应。
仅需一行代码,你就可以简化项目中数据请求的逻辑,并立即拥有以下这些不可思议的特性:
- 极速、轻量、可重用的 数据请求
- 内置 缓存 和重复请求去除
- 实时 体验
- 传输和协议不可知
- 支持 SSR / ISR / SSG
- 支持 TypeScript
- React Native
SWR 涵盖了性能,正确性和稳定性的各个方面,以帮你建立更好的体验:
- 快速页面导航
- 间隔轮询
- 数据依赖
- 聚焦时重新验证
- 网络恢复时重新验证
- 本地缓存更新 (Optimistic UI)
- 智能错误重试
- 分页和滚动位置恢复
- React Suspense
入门
安装
在 React 项目目录运行以下命令:
npm install swr
快速开始
对于返回 JSON 数据的普通 RESTful APIs,首先需要创建一个 fetcher
函数,这个函数只是原生 fetch
的包装:
const fetcher = (...args) => fetch(...args).then((res) => res.json())
然后你可以 import useSWR
并开始在任何函数组件中使用它:
import useSWR from "swr";
function Profile() {
const { data, error, isLoading } = useSWR("/api/user/123", fetcher)
if (error) return <div>failed to load</div>
if (isLoading) return <div>loading...</div>
// 渲染数据
return <div>hello {data.name}!</div>
}
可复用组件
在构建 web 应用时,你可能需要在 UI 的很多地方重用数据。在 SWR 上创建可重用的数据 hooks 非常容易:
function useUser(id) {
const { data, error, isLoading } = useSWR(`/api/user/${id}`, fetcher)
return {
user: data,
isLoading,
isError: error,
}
}
在组件中使用:
function Avatar({ id }) {
const { user, isLoading, isError } = useUser(id)
if (isLoading) return <Spinner />
if (isError) return <Error />
return <img src={user.avatar} />
}
全局配置
SWRConfig
可以为所有的 SWR hook 提供全局配置。
<SWRConfig value={options}>
<Component/>
</SWRConfig>
在以下示例中,所有的 SWR hook 都将使用提供的相同的 fetcher 来加载 JSON 数据,默认每 3 秒刷新一次:
import useSWR, { SWRConfig } from 'swr'
function Dashboard () {
const { data: events } = useSWR('/api/events')
const { data: projects } = useSWR('/api/projects')
const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // override
// ...
}
function App () {
return (
<SWRConfig
value={{
refreshInterval: 3000,
fetcher: (resource, init) => fetch(resource, init).then(res => res.json())
}}
>
<Dashboard />
</SWRConfig>
)
}
数据请求
const { data, error } = useSWR(key, fetcher)
这是 SWR 的基本 API。这里的 fetcher
是一个异步函数,它 接受 SWR 的 key
并返回数据。
返回值将作为 data
传递,如果抛出错误,将作为 error
被捕获。
axios
import axios from 'axios'
const fetcher = url => axios.get(url).then(res => res.data)
function App () {
const { data, error } = useSWR('/api/data', fetcher)
// ...
}
条件数据请求
按需请求
使用 null
或传一个函数作为 key
来有条件地请求数据。如果函数抛出错误或返回 falsy 值,SWR 将不会启动请求。
// 有条件的请求
const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)
// ...或返回一个 falsy 值
const { data } = useSWR(() => shouldFetch ? '/api/data' : null, fetcher)
// ... 或在 user.id 未定义时抛出错误
const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)
传入参数
参数
默认情况下,key
将作为参数传递给 fetcher
。所以下面这 3 个表达式是等价的:
useSWR('/api/user', () => fetcher('/api/user'))
useSWR('/api/user', url => fetcher(url))
useSWR('/api/user', fetcher)
多个参数
在某些场景中,向 fetcher
函数传递多个参数(可以是任何值或对象)非常有用。
例如授权请求:
useSWR('/api/user', url => fetchWithToken(url, token))
数据更改
SWR 提供了 mutate
和 useSWRMutation
两个 API 用于更改远程数据及相关缓存。
mutate
有两种方法可以使用 mutate
API 来进行数据更改,全局数据更改 API 可以更改任何 key 的数据,而绑定数据更改只能更改对应 SWR hook 的数据。
全局数据更改
推荐使用 useSWRConfig
hook 获取全局 mutator
:
import { useSWRConfig } from "swr"
function App() {
const { mutate } = useSWRConfig()
mutate(key, data, options)
}
全局引入它:
import { mutate } from "swr"
function App() {
mutate(key, data, options)
}
绑定数据更改
绑定数据更改可以更便捷的更改当前 key 数据,它的 key
与传递给 useSWR
的 key
相绑定,并接收 data
作为第一个参数。
它在功能上等同于上文提到的的全局 mutate
函数,但它不需要传入 key
参数:
import useSWR from 'swr'
function Profile () {
const { data, mutate } = useSWR('/api/user', fetcher)
return (
<div>
<h1>My name is {data.name}.</h1>
<button onClick={async () => {
const newName = data.name.toUpperCase()
// 发送请求给 API 以更新数据
await requestUpdateUsername(newName)
// 立即更新并重新验证本地数据(重新请求)
// 注意: 当使用 useSWR 的 mutate 时,key 并不是必须的,因为它已经预先绑定了。
mutate({ ...data, name: newName })
}}>Uppercase my name!</button>
</div>
)
}
Api
Parameters
-
key
:与useSWR
的key
相同,但函数表现为一个 过滤函数。 -
data
:用于更新客户端缓存的数据,或者是一个用于进行远程数据更改的异步函数。 -
options
:接受下列选项
optimisticData
:用于立即更新客户端缓存的数据,或是一个接受当前数据并返回新的客户端缓存数据的函数,通常用于乐观 UI。revalidate = true
:一旦异步更新完成,重新验证缓存。populateCache = true
:将远程数据更改的结果写入缓存,或者将接收新结果和当前结果作为参数并返回数据更改结果的函数。rollbackOnError = true
:如果远程数据更改失败,缓存会回滚。或者接受一个函数,它接收从 fetcher 抛出的错误作为参数,并返回一个布尔值判断是否应该回滚。throwOnError = true
:数据更改失败时抛出错误。
返回值
mutate
返回参数的 data
是被解析过的结果。传递给 mutate
的函数将返回一个更新后的数据,用于更新相应的缓存值。如果在执行函数时出现错误,错误将被抛出,以便进行合适的处理。
try {
const user = await mutate('/api/user', updateUser(newUser))
} catch (error) {
// 处理更新用户时出现的错误
}
useSWRMutation
SWR 还提供了 useSWRMutation
作为一个远程数据更改的 hook。远程数据更改只能手动触发,而不像 useSWR
那样会自动触发。
另外,这个 hook 不会与其他 useSWRMutation
hook 共享状态。
import useSWRMutation from 'swr/mutation'
// 实现 fetcher
// 额外的参数可以通过第二个参数 `arg` 传入
// 在下例中,`arg` 为 `'my_token'`
async function updateUser(url, { arg }) {
await fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${arg}`
}
})
}
function Profile() {
// 一个类似 useSWR + mutate 的 API,但是它不会自动发送请求
const { trigger } = useSWRMutation('/api/user', updateUser, options?)
return <button onClick={() => {
// 以特定参数触发 `updateUser` 函数
trigger('my_token')
}}>Update User</button>
}
Api
参数
-
key
: 与mutate
的key
相同 -
fetcher(key, { arg })
:一个用于远程数据更改的异步函数 -
options
:一个可选的对象,包含了下列属性:
optimisticData
:与mutate
的optimisticData
相同revalidate = true
:与mutate
的revalidate
相同populateCache = false
:与mutate
’ 的populateCache
相同 ,但默认值为false
rollbackOnError = true
:与mutate
的rollbackOnError
相同throwOnError = true
: 与mutate
’ 的throwOnError
相同onSuccess(data, key, config)
: 远程数据更改完成时的回调函数onError(err, key, config)
: 远程数据更改返回错误时的回调函数
返回值
data
:从fetcher
返回给定 key 的数据error
:fetcher
中抛出的错误(或 undefined)trigger(arg, options)
:一个用于触发远程数据更改的函数reset
:一个用于重置状态的函数(data
,error
,isMutating
)isMutating
:有一个正在进行中的远程数据变更
基本用法
import useSWRMutation from 'swr/mutation'
async function sendRequest(url, { arg }) {
return fetch(url, {
method: 'POST',
body: JSON.stringify(arg)
}).then(res => res.json())
}
function App() {
const { trigger, isMutating } = useSWRMutation('/api/user', sendRequest, /* options */)
return (
<button
disabled={isMutating}
onClick={async () => {
try {
const result = await trigger({ username: 'johndoe' }, /* options */)
} catch (e) {
// 错误处理
}
}}
>
Create User
</button>
)
}