我试图理解为什么以下 useEffect 在无限循环中运行。我创建了 fetchSchedule 辅助函数来调用 getSchedule 服务(使用 Axios 查询 API 端点)。我没有在 useEffect Hook 中定义此函数的原因是,我想在调用 onStatus 函数时也调用它(这会在单独的端点上切换 bool PUT 请求)。
eslinter 要求将 fetchSchedule
添加到依赖项数组中,这似乎触发了无限循环。
它应该工作的方式是在第一次渲染时从数据库中获取数据,然后仅在每次更新 value
属性或切换 onStatus
按钮时获取数据.
到目前为止,我的研究似乎表明这可能与 useEffect 与异步函数和闭包的行为方式有关。我仍在尝试理解 Hooks,显然我的代码中有些东西没有得到......
import React, { useEffect, useCallback } from 'react';
import useStateRef from 'react-usestateref';
import { NavLink } from 'react-router-dom';
import { getSchedule, updateStatus } from '../../services/scheduleService';
import Status from './status';
// import Pagination from './pagination';
const List = ({ value }) => {
// eslint-disable-next-line
const [schedule, setSchedule, ref] = useStateRef([]);
// const [schedule, setSchedule] = useState([]);
const fetchSchedule = useCallback(async () => {
const { data } = await getSchedule(value);
setSchedule(data);
}, [value, setSchedule]);
const onStatus = (id) => {
updateStatus(id);
fetchSchedule();
console.log('fetch', ref.current[0].completed);
};
useEffect(() => {
fetchSchedule();
}, [fetchSchedule]);
return (...)
最佳答案
2021 年 3 月更新
与 react-usestateref
的存储库所有者合作后,该软件包现在可以按照最初的预期运行,并且可以安全地用作 useState
自版本 的替代品>1.0.5
。当前的实现如下所示:
function useStateRef(defaultValue) {
var [state, setState] = React.useState(defaultValue);
var ref = React.useRef(state);
var dispatch = React.useCallback(function(val) {
ref.current = typeof val === "function" ?
val(ref.current) : val;
setState(ref.current);
}, []);
return [state, dispatch, ref];
};
如果没有这个react-usestateref
导入,你会没事的。
该钩子(Hook)返回一个用于设置状态的普通匿名函数,这意味着它将在每次渲染时重新创建 - 您不能将其有效地包含在任何依赖项数组中,因为它也会在每次渲染时更新。但是,由于该函数是从未知的自定义 Hook 返回的(并且无论如何,ESLint 都会正确识别它不是正确的 setter 函数),因此当您不这样做时,您会收到警告。
它试图解决的“问题”也会在您的代码中引入不良实践 - 这是避免正确处理依赖项的好方法,这些依赖项可以使您的代码更安全。
如果你回到标准状态 Hook ,我相信这段代码会正常工作。不要尝试在 onStatus
中获取状态的引用,而是使其异步并从 fetchSchedule 返回数据并设置它。
const [schedule, setSchedule] = useState([]);
const fetchSchedule = useCallback(async () => {
const { data } = await getSchedule(value);
setSchedule(data);
return data;
}, [value]);
const onStatus = async (id) => {
updateStatus(id);
const data = await fetchSchedule();
};
useEffect(() => {
fetchSchedule();
}, [fetchSchedule]);
或者,虽然我再次不建议使用它,但我们实际上可以编写一个安全版本的 useStateRef 钩子(Hook):
function useStateRef(defaultValue) {
var [state, setState] = React.useState(defaultValue);
var ref = React.useRef(defaultValue);
ref.current = state;
return [state, setState, ref];
}
状态设置函数在组件的整个生命周期中始终引用相同,因此可以将其包含在依赖项数组中,而不会导致重新创建效果/回调。
关于reactjs - 使用异步获取函数对无限循环的 useEffect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65782076/