yarn add swr
next.js
团队创建了一个名为swr
的react hook
,用于数据获取。如果您在客户端获取数据,我们强烈建议您使用这个hook
。它具有缓存,自动重新请求,窗口焦点跟踪,客户端周期性请求数据的功能。
api用法
const { data, error, isLoading, isValidating, mutate } = useSWR(key, fetcher, options)
useSWR
参数说明
key
: 请求的唯一 key
,类型可以是 string
、function
、array
、null
。fetcher
:(可选)一个请求数据的 Promise
返回函数。options
:(可选)该 SWR hook
的配置对象。useSWR
返回值说明
data
: 通过 fetcher
用给定的 key 获取的数据。error
: fetcher
抛出的错误。isLoading
: 是否有一个正在进行中的请求且当前没有 “已加载的数据”。预设数据及之前的数据不会被视为 “已加载的数据”。mutate(data?, options?)
: 更改缓存数据的函数。isValidating
: 是否有请求或重新验证加载。isLoading 和 isValidating 的区别
你可以使用任何请求库来处理数据请求,比如:fetch、axios、graphql等。
pages/api/user.js
接口文件,并新增内容如下// 为了使 API 路由能正常工作,你需要导出(export)一个默认函数 handler(即 请求处理器),并且该函数能够接收以下参数: req、res
export default function handler(req, res) {
return res
.status(200)
.json([
{ name: "John Doe1" },
{ name: "John Doe2" },
{ name: "John Doe3" },
]);
}
pages/ajax/index.jsx
路由组件,测试 swr
请求export default function Ajax() {
return <div className="Ajax"></div>;
}
import useSWR from "swr";
const fetcher = (url) => fetch(url).then((r) => r.json());
export default function Ajax() {
const { data, error, isLoading } = useSWR("/api/user", fetcher, {fallbackData: []}); // fallbackData: data变量的初始数据
if (isLoading) return <div className="Loading">loading...</div>;
if (error) return <div className="Error">{error.message}</div>;
return (
<div className="Ajax">
{data.map((item) => (
<h5 key={item.name}>{item.name}</h5>
))}
</div>
);
}
import useSWR from "swr";
import axios from "axios";
+ const fetcher = (url) => axios.get(url).then((r) => r.data);
- const fetcher = (url) => fetch(url).then((r) => r.json());
export default function Ajax() {
const { data, error, isLoading } = useSWR("/api/user", fetcher, {fallbackData: []}); // fallbackData: data变量的初始数据
if (isLoading) return <div className="Loading">loading...</div>;
if (error) return <div className="Error">{error.message}</div>;
return (
<div className="Ajax">
{data.map((item) => (
<h5 key={item.name}>{item.name}</h5>
))}
</div>
);
}
SWRConfig
组件可以为所有的SWR hook
提供全局配置,被该组件包裹的所有组件的内容,都会默认加载这些全局配置。
如果多个组件中都要使用
swr
发送请求,那每个组件文件中都要导入swr
,并设置一个fetcher
请求函数,比较繁琐,因此,可以将其配置在App
根组件的外部,这样所有的内部子组件都可以使用这个fetcher
发送请求了。
pages/_app.jsx
根组件内容import { SWRConfig } from "swr";
function App({ Component, pageProps }) {
return <SWRConfig
value={{
fetcher: (resource, init) =>
fetch(resource, init).then((res) => res.json()),
}}
>
{getLayout(<Component {...pageProps} title="额外的数据" />)}
</SWRConfig>
}
swr
时,默认使用全局配置import useSWR from "swr";
export default function Ajax() {
const { data, error, isLoading } = useSWR("/api/user"); // 如果 fetcher 是全局配置 `<SWRConfig>` 提供的,第二个参数可以忽略。
return (
<div className="Ajax">
...
</div>
);
}
你总是可以响应性的在组件内部得到 error 对象。但如果你想要全局处理错误,通知 UI 显示一个 toast 或者一个 snackbar,或在某处收集它,可以用 onError 事件:
<SWRConfig value={{
onError: (error, key) => {
if (error.status !== 403 && error.status !== 404) {
// 显示一个通知 UI。
}
}
}}>
<MyApp />
</SWRConfig>
当你重新聚焦一个页面或在标签页之间切换时,SWR 会自动重新请求数据。这个功能非常实用,可以保持网站同步到最新数据。对于在长时间位于后台的标签页,或 休眠 的电脑等情况下刷新数据也很有帮助。该特性默认是启用的。你可以通过 revalidateOnFocus 选项禁用它。
const { data, error, isLoading } = useSWR("/api/user", {
revalidateOnFocus: false, // 窗口聚焦时自动重新请求
});
SWR 会为你提供定时重新请求数据的选项。以达到轮询的目的。
const { data } = useSWR("/api/user", {
refreshInterval: 1000,
});
在用户解锁了他们的计算机但网络还没有连上时。为了确保页面数据始终是最新的,SWR 会在网络恢复时自动重新请求。
该特性默认是启用true。你可以通过 revalidateOnReconnect
选项禁用它。
const { data } = useSWR("/api/user", {
revalidateOnReconnect: false,
});
如果数据是不变的,即使我们重新请求也永远不会发生任何改变,那么我们可以禁用它的所有的自动重新请求,直接将请求结果缓存即可。
useSWRImmutable
来标记数据为不可变数据。import useSWRImmutable from 'swr/immutable'
useSWRImmutable(key, fetcher, options)
const { data } = useSWR(key, fetcher, {
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnReconnect: false
})
// 相当于
const { data } = useSWRImmutable(key, fetcher)
在某些场景中,可能向 fetcher 函数传递多个参数(可以是任何值或对象),你可以使用一个数组作为参数 key,它包含 fetcher 的多个参数。
useSWR('/api/user', fetcher)
useSWR('/api/user', url => fetcher(url))
const {data} = useSWR(['/api/user', 参数], fetcher);
const { data } = useSWR(['/api/user', 参数], ([url, 参数]) => fetcher(url, 参数));
import useSWR from "swr";
const fetcher = async (urls) => {
const [url, token] = urls;
return fetch(`${url}?token=${token}`).then((r) => r.json());
};
export default function Ajax() {
const { data } = useSWR(["/api/user", "token"], fetcher);
return (
<div className="Ajax">
{data && data.map((item) => <h5 key={item.name}>{item.name}</h5>)}
</div>
);
}
import useSWR from "swr";
import { useState } from "react";
const fetcher = async (url) => fetch(url).then((r) => r.json());
export default function Ajax() {
const [page, setPage] = useState(1); // 分页页码
const { data } = useSWR(`/api/daniu?page=${page}`, fetcher, {
fallbackData: [],
// revalidateOnFocus: false, // 窗口聚焦时自动重新请求。
// dedupingInterval: 2000, // 删除一段时间内相同 key 的重复请求(以毫秒为单位),默认2000。可以不配置,不配置在进行快速切换分页的时候,同一个url的请求在2秒以内不会重复发送。设置为0,每次点击分页按钮都会发送请求。
});
return (
<div className="Ajax">
<div className="btns">
<button onClick={() => setPage(page - 1)}>上一页</button>
<button onClick={() => setPage(page + 1)}>下一页</button>
</div>
{data.course &&
data.course.data.map((item) => <h5 key={item.id}>{item.title}</h5>)}
</div>
);
}