NextJs:在 React useEffect Hook 内使用变量调用 setInterval
Posted
技术标签:
【中文标题】NextJs:在 React useEffect Hook 内使用变量调用 setInterval【英文标题】:NextJs: Calling setInterval with a variable for time inside of a React useEffect Hook 【发布时间】:2021-07-04 17:40:21 【问题描述】:我有一个名为 fetchData 的函数。其目的是根据 api 端点参数检索数据并根据间隔参数更新该数据。
import useState, useEffect from 'react';
export const fetchData = (endpoint, interval) =>
const [jsonData, setJsonData] = useState(null);
useEffect(() =>
const innerFetchData = async () =>
fetch(endpoint,
method: 'GET',
headers:
'Content-Type': 'application/json',
,
)
.then((res) => res.json())
.then((data) => data)
.then((moreData) => setJsonData(moreData))
.catch((e) => console.error(e));
;
innerFetchData();
const timer = setInterval(() =>
innerFetchData();
, interval);
return () => clearInterval(timer);
, []);
return jsonData;
;
我正在导入它并在我的一个反应组件中使用它
const data = fetchData('/api/CustomerWorkspace', 5000);
出了什么问题,我认为它没有正确读取间隔参数,当我运行它时,它可能每秒无限调用 api 50 次。如果我在 fetchData 内部的计时器上硬编码间隔时间,它可以正常工作。你能帮我弄清楚如何传入一个区间变量,以便我可以在不同的组件中重用 fetchData 吗?谢谢。
【问题讨论】:
【参考方案1】:如果您只在 setInterval 内调用 innerFetchData();
,那么它会正常工作。你在 useEffect 中调用了两次innerFetchData()
【讨论】:
我不明白为什么会这样,但这确实是一个奇怪的设置。无论如何,仅仅删除它并不能完全修复,因为现在它只在间隔中运行,所以,不要在第一次渲染中运行。你不小心删除了代码的一个重要行为。【参考方案2】:尝试使用 useInterval
,这是一个自定义钩子,可以处理此浏览器 API 和 React 的一些奇怪问题。
短:https://www.30secondsofcode.org/react/s/use-interval
完整解释:https://overreacted.io/making-setinterval-declarative-with-react-hooks/
已应用演示:
// file: useInterval.js
export const useInterval = (callback, delay) =>
const savedCallback = React.useRef();
React.useEffect(() =>
savedCallback.current = callback;
, [callback]);
React.useEffect(() =>
function tick()
savedCallback.current();
if (delay !== null)
let id = setInterval(tick, delay);
return () => clearInterval(id);
, [delay]);
;
// your file
// import useEffect, useState, useCallback from "react"
// import useInterval from "./useInterval"
export const fetchData = (endpoint, interval) =>
const [jsonData, setJsonData] = useState(null);
const innerFetchData = useCallback(
// if you gonna use `.then` you don't need the async in here tho
async () =>
fetch(endpoint,
method: 'GET',
headers:
'Content-Type': 'application/json',
,
)
.then((res) => res.json())
.then((data) => data)
.then((moreData) => setJsonData(moreData))
.catch((e) => console.error(e));
,
[endpoint]
);
// runs once
useEffect(() =>
innerFetchData();
, []);
// runs every `interval`
useInterval(() =>
innerFetchData();
, interval);
return jsonData;
;
如果你愿意,你也可以把这个 fetchData 函数放在一个钩子里,只要调用它useFetchData
,用法是一样的。不要改变我认为的任何东西,但我认为它更花哨的 xP
【讨论】:
【参考方案3】:每次调用innerFetchData()
,它都会通过setJsonData
设置状态。这会触发重新渲染,导致 useEffect 删除您已经设置的间隔并立即创建一个新的。因此,您的时间间隔可能设置正确,但在每次请求时都会被清除。
您应该将计时器存储在useRef
中。这将有助于它在组件的整个生命周期中持续存在。
【讨论】:
以上是关于NextJs:在 React useEffect Hook 内使用变量调用 setInterval的主要内容,如果未能解决你的问题,请参考以下文章
React/NextJS 使用 UseEffect 错误:渲染的钩子比上一次渲染期间更多
NextJS Router & Jest:如何模拟路由器更改事件