使用React 16.8.6(在之前的版本16.8.3上很好),当我试图阻止fetch请求上的无限循环时,我得到了这个错误:
./src/components/BusinessesList.js
Line 51: React Hook useEffect has a missing dependency: 'fetchBusinesses'.
Either include it or remove the dependency array react-hooks/exhaustive-deps
我一直无法找到一个解决办法来停止这个无限循环。我想远离使用useReducer()。我确实找到了关于'筋疲力尽-deps' lint规则#14920的讨论[ESLint]反馈,其中一个可能的解决方案是,如果你认为你知道你在做什么,你可以总是// ESLint - disabled -next-line react-hooks/详尽-deps。我对我正在做的事情没有信心,所以我还没有尝试实现它。
我有这个当前的设置,React钩子useEffect连续运行永远/无限循环,唯一的评论是关于useCallback(),我不熟悉。
我目前如何使用useEffect()(我只想在开始时运行一次,类似componentDidMount()):
useEffect(() => {
fetchBusinesses();
}, []);
const fetchBusinesses = () => {
return fetch("theURL", {method: "GET"}
)
.then(res => normalizeResponseErrors(res))
.then(res => {
return res.json();
})
.then(rcvdBusinesses => {
// some stuff
})
.catch(err => {
// some error handling
});
};
您可以删除第二个参数类型数组[],但fetchBusinesses()也将在每次更新时被调用。如果愿意,可以在fetchBusinesses()实现中添加IF语句。
React.useEffect(() => {
fetchBusinesses();
});
另一个方法是在组件外部实现fetchBusinesses()函数。如果有的话,不要忘记将任何依赖参数传递给fetchBusinesses(依赖项)调用。
function fetchBusinesses (fetch) {
return fetch("theURL", { method: "GET" })
.then(res => normalizeResponseErrors(res))
.then(res => res.json())
.then(rcvdBusinesses => {
// some stuff
})
.catch(err => {
// some error handling
});
}
function YourComponent (props) {
const { fetch } = props;
React.useEffect(() => {
fetchBusinesses(fetch);
}, [fetch]);
// ...
}
如果你正在创建一个新的应用程序或有足够的灵活性,有非常好的状态管理库的选择。看看《后坐力》。
为了完整起见:
1. (停止工作)使用函数作为useEffect回调
useEffect(fetchBusinesses, [])
2. 在useEffect()中声明函数
useEffect(() => {
function fetchBusinesses() {
...
}
fetchBusinesses()
}, [])
3.使用useCallback()进行记忆
在这种情况下,如果你的函数中有依赖项,你必须将它们包含在useCallback依赖项数组中,如果函数的参数改变,这将再次触发useEffect。此外,这是一大堆样板文件……因此,只需像1中那样将函数直接传递给useEffect。useEffect (fetchBusinesses[])。
const fetchBusinesses = useCallback(() => {
...
}, [])
useEffect(() => {
fetchBusinesses()
}, [fetchBusinesses])
4. 函数的默认实参
正如Behnam Azimi所说
这不是最佳实践,但在某些情况下可能有用。
useEffect((fetchBusinesses = fetchBusinesses) => {
fetchBusinesses();
}, []);
5. 创建自定义钩子
创建一个自定义钩子,并在只需要运行一次函数时调用它。它可能更干净。你也可以在需要时返回一个回调来重置重新运行“初始化”。
// customHooks.js
const useInit = (callback, ...args) => {
const [mounted, setMounted] = useState(false)
const resetInit = () => setMounted(false)
useEffect(() => {
if(!mounted) {
setMounted(true);
callback(...args);
}
},[mounted, callback]);
return [resetInit]
}
// Component.js
return ({ fetchBusiness, arg1, arg2, requiresRefetch }) => {
const [resetInit] = useInit(fetchBusiness, arg1, arg2)
useEffect(() => {
resetInit()
}, [requiresRefetch, resetInit]);
6. 禁用eslint的警告
禁用警告应该是您最后的手段,但是当您这样做时,最好是内联且显式地执行,因为未来的开发人员可能会感到困惑,或者在不知道linting关闭的情况下创建意外的错误
useEffect(() => {
fetchBusinesses()
}, []) // eslint-disable-line react-hooks/exhaustive-deps
实际上,在使用钩子进行开发时,警告非常有用。但在某些情况下,它会刺痛你。特别是当您不需要监听依赖项更改时。
如果你不想将fetchBusinesses放在钩子的依赖项中,你可以简单地将它作为参数传递给钩子的回调函数,并将fetchBusinesses设置为它的默认值,如下所示:
useEffect((fetchBusinesses = fetchBusinesses) => {
fetchBusinesses();
}, []);
这不是最佳实践,但在某些情况下可能有用。
同样,正如Shubham所写的,你可以添加下面的代码来告诉ESLint忽略钩子的检查。
// eslint-disable-next-line react-hooks/exhaustive-deps
你可以这样尝试:
const fetchBusinesses = () => {
return fetch("theURL", {method: "GET"})
.then(res => normalizeResponseErrors(res))
.then(res => {
return res.json();
})
.then(rcvdBusinesses => {
// Some stuff
})
.catch(err => {
// Some error handling
});
};
and
useEffect(() => {
fetchBusinesses();
});
这对你有用。
但我的建议是试试这种方法,它也适用于你。
这比以前的方法好。我是这样用的:
useEffect(() => {
const fetchBusinesses = () => {
return fetch("theURL", {method: "GET"})
.then(res => normalizeResponseErrors(res))
.then(res => {
return res.json();
})
.then(rcvdBusinesses => {
// Some stuff
})
.catch(err => {
// Some error handling
});
};
fetchBusinesses();
}, []);
如果您根据特定的id获取数据,则在回调中添加useEffect [id]。然后它就不能显示警告
React钩子useEffect有一个缺失的依赖:'any thing'。要么包含它,要么删除依赖数组
React也给出了解决方案。他们建议你使用useCallback,它会返回你函数的一个内存版本:
'fetchBusinesses'函数使useEffect钩子(在NN行)的依赖关系在每次渲染时发生变化。为了解决这个问题,将'fetchBusinesses'定义包装到它自己的useCallback() Hook react-hooks/竭-deps中
useCallback使用起来很简单,因为它与useEffect具有相同的签名。区别在于useCallback返回一个函数。
它看起来是这样的:
const fetchBusinesses = useCallback( () => {
return fetch("theURL", {method: "GET"}
)
.then(() => { /* Some stuff */ })
.catch(() => { /* Some error handling */ })
}, [/* deps */])
// We have a first effect that uses fetchBusinesses
useEffect(() => {
// Do things and then fetchBusinesses
fetchBusinesses();
}, [fetchBusinesses]);
// We can have many effects that use fetchBusinesses
useEffect(() => {
// Do other things and then fetchBusinesses
fetchBusinesses();
}, [fetchBusinesses]);