react-demo:实现每隔60s刷新一次接口
首先:不喜勿喷。3Q。祝您生活愉快。
Q: 为什么突然想写这个demo?
A: 是因为我在练习自定义hook时想要写个例子,而这个场景是我真实遇见的。
如今想要用一种自定义hook实现该demo,而不是直接设置60s定时器再次请求接口。
我要实现的场景是:
在页面只挂载一次,不会再次刷新页面的情况下,实现每隔1min便会更新一下数据。
demo搭建
假如说,我想实现的就是每60s就改变一下count,使其+1。
且只挂载一次页面还要实现60s更新,那么如果我这么写呢?
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
console.log(count)
setCount(count+1)
}, 60000);
return () => clearInterval(interval);
},[])
return (
<>
<div>count计数器: {count}</div>
</>
);
你觉得行吗?看起来好像没什么问题,每个60s使count+1然后显示在界面上没毛病啊?
你自己看!(甄嬛传滴血验亲语气)
它在dom中显示的count已经被挂载+1,而钩子函数中的count打印出的始终为0,不会进行+1的操作。
那我怎么实现更新数据啊??
我想到的是通过赋值ref.current来存储数据的更新,于是定义了一个钩子函数将原来的count就挂载到ref.current中,此后的每次更新都在ref的基础上,那么看下书写倒是很简单了。
export const useLatestValue = (value) => {
const ref = useRef(value);
ref.current = value;
return ref;
};
只需要将count入参useLatestValue(count)即可开启ref挂载之路。
那么回到定时器中继续补全:
export default () => {
const [count, setCount] = useState(0);
const ref = useLatestValue(count);
useEffect(() => {
const interval = setInterval(() => {
console.log("count:", count);
setCount(ref.current + 1);
}, 60000);
return () => clearInterval(interval);
}, []);
return (
<>
<div>count计数器: {count}</div>
</>
);
};
另外也可以把自定义钩子函数的入参进行ts类型约束,由于该钩子函数可能会作为一个公共函数来使用,所以无论入参为什么形式,都需要保证出参都是相同的类型,那么这种情况就用到了泛型。
export const useLatestValue = <T>(value:T):{current:T} => {
const ref = useRef(value);
ref.current = value;
return ref;
};
线上书写:
原始实现方法:直接在定时器中请求接口:
function ApiRefresh() {
// 初始化为null,避免渲染时出现undefined的情况
const [apiResponse, setApiResponse] = useState<ApiResponse | null>(null);
const [loading, setLoading] = useState(false); // 控制loading状态
// 显示接口返回值的姓名,如果为空则显示Loading...
return <div>{apiResponse ? apiResponse.name : "Loading..."}</div>;
}
在组件加载完成后,通过setInterval
定时刷新接口数据
interface ApiResponse {
// 假设接口返回的是一个包含name和age字段的对象
name: string;
age: number;
}
function ApiRefresh() {
const [apiResponse, setApiResponse] = useState<ApiResponse | null>(null);
const [loading, setLoading] = useState(false);
// 在组件加载完成后,每隔60s刷新一次接口
useEffect(() => {
setLoading(true); // 刷新时,显示loading状态
const timer = setInterval(() => {
axios.get<ApiResponse>("https://example.com/api").then(response => {
setApiResponse(response.data);
setLoading(false); // 刷新完成后,隐藏loading状态
});
}, 60000);
// 组件卸载时,清除定时器
return () => clearInterval(timer);
}, []);
return <div>{apiResponse ? apiResponse.name : (loading ? "Loading..." : "")}</div>;
}
在上面的代码中,我们使用useEffect
钩子来监听组件的创建和销毁,然后在组件创建时初始化定时器,使用setInterval
函数每隔60s发送一次请求并更新状态,而在组件销毁时则清除定时器,避免不必要的网络请求。同时,我们也处理了接口数据的加载状态,避免用户等待时看到空白界面。
转载自:https://juejin.cn/post/7239715295485263933