swr 的问题
在 swr 中,使用非常简单,一个简单的 demo 如下:
import { useState } from "react";
import useSWR from "swr";
function App() {
const [status, setStatus] = useState(false);
const request = (status, stringKey, numberKey) => {
// 为了模拟实际中 api 的时长随机性,随机 1.5s 或 3s 后得到响应
const time = Math.random() > 0.5 ? 3000 : 1500;
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(time);
}, time);
});
};
const { data, error } = useSWR([status, "ss", 2], request);
return (
<>
{!data && <div>loading...</div>}
{error && <div>error...</div>}
{data && <div>{data}</div>}
<button
onClick={() => {
// 通过改变 swr 的唯一 key,也就是 [status, 'ss', 2] 中的 status
// 实现重新触发 api 请求的效果
setStatus((pre) => !pre);
}}
>
click
</button>
</>
);
}
下面来细数一下:
loading 态不健壮
首先就是 loading 态,swr 我们只能用 data 的有无去判断是否在 loading,或者单独维护一个初始为 true 的
state 去表示 loading,在 swr 的 onSuccess 处给他置为 false。
但我们要一个初始 data 的话,使用 !data 直接不攻自破,我们只能多次切换加载数据,在每次切换我都要手动将
state 置为 true,这也太麻烦了,不友好。
请求函数收参不健壮
我们在请求函数 request 中,如果 useSWR 的唯一标识是数组,那么传入请求函数参数的顺序是被解构后的!
// 唯一标识 [status, 'ss', 2]
const { data, error } = useSWR([status, 'ss', 2], request)
// ↓ 这里传入是被解构后的唯一标识
const request = (status, stringKey, numberKey) => {}
request函数参数必须把标识中的每一个item都占位了,
如果不占,则只能用arguments[x]
还需要根据restful语法自己设计stringKey
数据一致性场景中主动性差
特别是在筛选查询时,我们的 api 请求时长往往是不同的,当用户在 A 筛选条件下查询了数据,api 还未返回时,又
进行了筛选条件 B 的查询,此时又执行筛选条件 C 的查询,那么如此往复,每次切换都面临着预期显示数据和真实显示
数据不一致的问题。
因为界面上实际显示的数据只是最晚那一次 api 到达的数据,所以使用 axios 产生了数据不一致问题。
axios 确实有 cancel 的 token 方法,可以取消请求,umi-request 也有高阶的封装,但是每个方法都给我一个
cancel 方法这成本也太高了,在非昂贵成本的查询下,有没有一种忽略之前查询的方法?
答案是有的, 对一个 useSWR 来说,总是会忽略之前的请求,采用最新一次请求的结果,这是 swr 做的好的地方,可
是对于昂贵请求,swr 不能真正的取消请求。
其次,什么时候取消,什么时候又再去获取,在 swr 中要主动获取,一律要通过唯一 key 去控制,唯一 key 意味着
state,增加一大堆 useState 是非常不友好的。
其实 swr 的功能实在是太弱小了,现在开始我们有更强大的选择。