使用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设置为它的默认值,如下所示:
useEffect((fetchBusinesses = fetchBusinesses) => {
fetchBusinesses();
}, []);
这不是最佳实践,但在某些情况下可能有用。
同样,正如Shubham所写的,你可以添加下面的代码来告诉ESLint忽略钩子的检查。
// eslint-disable-next-line react-hooks/exhaustive-deps
在我的例子中,它对我的局部变量组织有这个警告,当我把组织放在依赖数组中时,useEffect将获取无限。因此,如果你有一些像我这样的问题,使用useEffect和依赖数组并拆分:
因为如果您有多个修改状态的API调用,它会多次调用useEffect。
来自:
const { organization } = useSelector(withOrganization)
const dispatch = useDispatch()
useEffect(() => {
dispatch(getOrganization({}))
dispatch(getSettings({}))
dispatch(getMembers({}))
}, [dispatch, organization])
To:
const { organization } = useSelector(withOrganization)
const dispatch = useDispatch()
useEffect(() => {
dispatch(getOrganization({}))
dispatch(getSettings({}))
}, [dispatch, organization])
useEffect(() => {
dispatch(getMembers({}))
}, [dispatch])
你可以这样尝试:
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'。要么包含它,要么删除依赖数组
您可以删除第二个参数类型数组[],但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]);
// ...
}
如果在useEffect中使用的变量是在组件内部定义的,或者是作为道具传递给组件的,则会发生此警告。因为你在同一个组件中定义了fetchBusinesses(),而eslint遵循这一规则,你必须将它传递给依赖数组。但在您的情况下,只传递[]也可以
在这种情况下,它将工作,但如果fetchBusinesses在函数中使用setState,并且调用它将重新呈现组件,因此您的fetchBusinesses将改变,因此useEffect将运行,这将创建一个无限循环。因此,仅仅盲目地遵循eslint可能会导致额外的错误。
用例解决方案让eslint满意,使用useCallback和[]。
const memoizedFetchBusinesses=useCallback(
fetchBusinesses,
[] // unlike useEffect you always have to pass a dependency array
)
当组件第一次呈现时,在内存中创建一个名为fetchBusinessess的函数,并创建memoizedFetchBusinesses变量,该变量也在内存中引用相同的函数。
在第一次渲染之后,一个被称为fetchbusiness的函数将再次被创建,但这一次在不同的内存位置,因为我们在useCallback中有[],memoizedFetchBusinesses将在相同的内存中给你原始的fetchBusinesses函数。这里的useCallback将为您提供在组件的第一次呈现中创建的相同的函数引用。
useEffect(()=>{
memoizedFetchBusinesses();
},[memoizedFetchBusinesses])
相反,你可以这样定义函数
const fetchBusinesses = useCallback(() => {
return fetch("theURL", {method: "GET"}
)
.then(res => normalizeResponseErrors(res))
.then(res => {
return res.json();
})
.then(rcvdBusinesses => {
// some stuff
})
.catch(err => {
// some error handling
});
},[]);
然后在useEffect中
useEffect(() => {
fetchBusinesses();
}, [fetchBusinesses]);
你正在使用useEffect,当你这样做的时候,你经常会想要使用一些变量作为你的组件中的道具或状态。
eslint中有一个规则,它希望你引用useEffect依赖数组中任何不同的道具或状态块。这是控制何时执行useEffect的数组。该规则希望看到它列在数组中,数组决定何时重新运行useEffect函数。
因此,您需要添加[fetchBusinesses],这样警告就会消失。
为什么这个规则要我们把它写在这里?
在某些情况下,使用useEffect而没有正确列出数组内的所有状态和道具,可能会导致奇怪且难以调试的问题。
因此,这条规则有助于避免使用useEffect可能出现的那些难以理解的问题。
现在,任意添加到该数组也会导致错误。所以无论哪种方式,你都遇到了必须解决的bug。根据你的评论,似乎为你解决了这个问题,但我想进一步调查,看看你是否有机会在你的网络选项卡在Chrome中添加fetchBusinesses函数到你的useEffect数组后得到第二个GET请求。