我可以在useEffect中调用另一个单独的函数吗?
我正在iuseEffect中调用另一个函数,但是保存文件后,它会自动将该函数添加到useEffect的数组参数中。
请参阅下面的代码以获得适当的理解。
保存文件之前
useEffect(() => {
getData()
console.log("useEffect ran...");
}, [query]);
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
保存文件后
useEffect(() => {
getData();
console.log("useEffect ran...");
}, [getData, query]);
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
它一次又一次地运行。
答案 0 :(得分:15)
TL; DR
使用useCallback()
首先,让函数成为依赖项是非常危险的。如果该函数导致状态改变,则随后的重新渲染将再次调用该函数(通过useEffect)...,并开始无限循环。
您可以做的一件事,正如许多人在此处建议的那样,是在useEffect()方法本身内创建函数。
useEffect(() => {
function getData() {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}
}
getData();
console.log("useEffect ran...");
}, [query]);
}
或者简单地
useEffect(() => {
(() => {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json)
)();
}, [query]);
}
话虽如此,有时您仍想在useEffect之外声明函数以进行代码重用。这次您需要确保在每个渲染期间都不会重新创建它。为此,您可以
在组件外部声明函数-迫使您将所有变量作为参数传递....这很痛苦
将其包装在useMemo()
或useCallback()
这是一个例子
const getData = useCallback(()=>{...}, []);
答案 1 :(得分:1)
被接受的答案在某种程度上具有误导性。组件内部的定义函数显然会在每个渲染器上重新创建。但这并不意味着在使用useEffect挂钩时,它将在每个渲染中重新调用。
保存文件代码后的关键问题是您正在寻找getData。在每个渲染上重新创建它时,useEffect接受它作为更改,从而导致您在每个渲染上重新运行。 简单的解决方法是不观看getData。
但是显然,正如接受的答案所建议的那样。最好在组件外部分离函数,以免在每个渲染器上重新创建函数。
坦白说,如果我是你,我不会仅仅为获取定义函数:
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json())
.then(json => setData(json));
}, [query]); // only re-run on query change
答案 2 :(得分:0)
自从在React组件内声明getData
函数以来,它将在每个渲染器上重新创建,因此效果的依赖性在每个渲染器上都会改变。这就是为什么要在每个渲染器上执行效果的原因。
为防止这种情况,您应该在组件外部声明getData
函数,然后传递查询。像这样:
function getData(query) {
return fetch(`https://jsonplaceholder.typicode.com/${query}`)
.then(response => response.json());
}
function YouComponent({ query }) {
...
useEffect(() => {
getData(query).then(setData);
console.log("useEffect ran...");
}, [query]);
...
P.S:我不确定eslint插件在这样做时是否会自动将getData添加到依赖项中,即使这样做也不会造成伤害。
答案 3 :(得分:0)
如果将getData
函数移到useEffect
内,则不必将其包括为依赖项,并且useEffect
仅在query
更改时运行。 / p>
答案 4 :(得分:0)
尝试将getData函数包装在useCallback钩子中并将其放在组件外部,因此当调用getData时,它将不会一直返回新函数,因此将阻止组件重新渲染