如何使用React钩子和使用UseInterval设置状态
我了解使用Interval使您可以将功能组件作为参数传递,因此我试图利用它,并设置具有功能组件中使用的值的设置状态。 在以下代码中,我希望ExecutionsPage获取ProjectScans和IsProjectScansFetchComplete,它们从usefetfethprojectprojectscansbyuser()挂接作为数组中返回:
1 const ExecutionsPage: React.FC = () => {
2 let user:string|null = sessionStorage.getItem('user')
3 const UPDATE_TABLE_TIMER: number = 30000; // Time (ms) until we call the API again to update the scans table
4 const [stateProjectScans, setStateProjectScans] = useState<Array<IProjectScan>>([]);
5 const [stateIsProjectScansFetchComplete, setStateIsProjectScansFetchComplete] = useState<boolean>(false);
6 function CallProjectScans(){
7 let [projectScans, isProjectScansFetchComplete] = useFetchProjectScansByUser(user)
8 return [projectScans, isProjectScansFetchComplete]
9 }
10 useEffect(() => {
11 let [projectScans, isProjectScansFetchComplete] = CallProjectScans()
12 // @ts-ignore
13 setStateProjectScans(projectScans)
14 // @ts-ignore
15 setStateIsProjectScansFetchComplete(isProjectScansFetchComplete)
16 }, [])
17 const GetProjectScans = () => {
18 let [projectScans, isProjectScansFetchComplete] = useFetchProjectScansByUser(user);
19 setStateProjectScans(projectScans)
20 };
21 // @ts-ignore
22 useInterval(GetProjectScans(), UPDATE_TABLE_TIMER)
在使用此代码时,我会遇到此错误:“错误:“重新订阅者太多。限制了防止无限循环的渲染数。” 因此,话虽如此,这是我的问题:
- 在可读性方面,我使用的功能太多了吗?
- 目的是每30秒钟在第7行上调用React Hook,并在第4和5行上更新州。是否有比我当前尝试的更好的方法了?
- 我尝试使用useseffect()来防止上述错误(通过将状态设置为executionspage的初始渲染,而不是重新读取它),但是我仍然可以得到它。为什么?
编辑:这是usefetchprojectscansbyuser()的函数定义:
export const useFetchProjectScansByUser = (user: string|null): [IProjectScan[], boolean] => {
const [projectScans, setProjectScans] = useState<IProjectScan[]>([]);
//update here
const [isProjectScansFetchComplete, setIsProjectScansFetchComplete] = useState<boolean>(false);
const {enqueueSnackbar, } = useSnackbar();
useEffect(() => {
...
/*function callJSONFunction(json) {
let projectScans: IProjectScan[] = createProjectScansFromJSON(json);
setProjectScans(projectScans);
}*/
const fetchProjectScans = async () => {
try {
const response = await fetch(URL);
if (!response.ok) throw response.statusText;
const json = await response.json();
let projectScans: IProjectScan[] = createProjectScansFromJSON(json);
setProjectScans(projectScans);
...
finally {
setIsProjectScansFetchComplete(true);
}
};
fetchProjectScans();
}
}, []);
return [projectScans, isProjectScansFetchComplete];
}
I understand useInterval allows you to pass functional components as parameters, so I'm trying to take advantage of that and setting states with values used inside a functional component.
In the following code, I want the ExecutionsPage to fetch projectScans and isProjectScansFetchComplete, which are returned from the useFetchProjectScansByUser() hook as an array:
1 const ExecutionsPage: React.FC = () => {
2 let user:string|null = sessionStorage.getItem('user')
3 const UPDATE_TABLE_TIMER: number = 30000; // Time (ms) until we call the API again to update the scans table
4 const [stateProjectScans, setStateProjectScans] = useState<Array<IProjectScan>>([]);
5 const [stateIsProjectScansFetchComplete, setStateIsProjectScansFetchComplete] = useState<boolean>(false);
6 function CallProjectScans(){
7 let [projectScans, isProjectScansFetchComplete] = useFetchProjectScansByUser(user)
8 return [projectScans, isProjectScansFetchComplete]
9 }
10 useEffect(() => {
11 let [projectScans, isProjectScansFetchComplete] = CallProjectScans()
12 // @ts-ignore
13 setStateProjectScans(projectScans)
14 // @ts-ignore
15 setStateIsProjectScansFetchComplete(isProjectScansFetchComplete)
16 }, [])
17 const GetProjectScans = () => {
18 let [projectScans, isProjectScansFetchComplete] = useFetchProjectScansByUser(user);
19 setStateProjectScans(projectScans)
20 };
21 // @ts-ignore
22 useInterval(GetProjectScans(), UPDATE_TABLE_TIMER)
In using this code, I'm getting this error: "Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."
So, with all that said, here are my questions:
- Readability-wise, am I using too many functions?
- The goal is to call the React hook on line 7 every 30 seconds and update the states on lines 4 and 5. Is there a better way to do this than how I'm currently attempting it?
- I tried using useEffect() to prevent the aforementioned error (by setting the states on the initial render of the ExecutionsPage, instead of rerendering it), but I am still getting it. Why?
Edit: Here's the function definition of useFetchProjectScansByUser():
export const useFetchProjectScansByUser = (user: string|null): [IProjectScan[], boolean] => {
const [projectScans, setProjectScans] = useState<IProjectScan[]>([]);
//update here
const [isProjectScansFetchComplete, setIsProjectScansFetchComplete] = useState<boolean>(false);
const {enqueueSnackbar, } = useSnackbar();
useEffect(() => {
...
/*function callJSONFunction(json) {
let projectScans: IProjectScan[] = createProjectScansFromJSON(json);
setProjectScans(projectScans);
}*/
const fetchProjectScans = async () => {
try {
const response = await fetch(URL);
if (!response.ok) throw response.statusText;
const json = await response.json();
let projectScans: IProjectScan[] = createProjectScansFromJSON(json);
setProjectScans(projectScans);
...
finally {
setIsProjectScansFetchComplete(true);
}
};
fetchProjectScans();
}
}, []);
return [projectScans, isProjectScansFetchComplete];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如预期的那样,您的钩子使用状态存储了对服务器的最后一个调用的结果。
如果要修改/更新该状态,则应通过添加新状态变量并将其传递到依赖项数组中,以
usefect
fired fire。然后,您可以将其转移回挂钩呼叫者以更新该依赖项数组的方式,因此实际上您可以从钩子外部控制更新。这正是钩子应该如何工作的方式:将逻辑划分,并将简单的API暴露于钩子的消费者。
As expected, your hook uses state to store the results of the last call to the server.
If you want to modify/update that state, you should make your sever call in the
useEffect
fire again by adding a new state variable and passing it to the dependency array. You can then pass back to the hook caller a way to update that dependency array, so in effect you can control the update from outside the hook.This is exactly how hooks should work: compartmentalize logic, and expose a simple API to the consumers of the hook.
钩子的第一个规则之一是:仅在顶级呼叫挂钩
因此,您需要更改代码,并将每个React挂钩移至顶部。如文档中所述,您甚至无法在另一个钩子之前返回。无论如何,要修复代码,您需要从功能内部删除React Hook
UsefetchProtchScansByuser
。One of the first rules of hooks is: Only Call Hooks at the Top Level
So, you'd need to change your code and move every React hook to the top. As stated in the docs you cannot even return earlier before another hook. Anyway, to fix the code then you need to remove the React hook
useFetchProjectScansByUser
from inside the functions.