ReactJS:如何只调用一次 useEffect 挂钩来获取 API 数据
Posted
技术标签:
【中文标题】ReactJS:如何只调用一次 useEffect 挂钩来获取 API 数据【英文标题】:ReactJS: how to call useEffect hook only once to fetch API data 【发布时间】:2019-08-24 07:49:36 【问题描述】:使用 React,我有以下使用 useEffect()
的功能组件:
import React, useEffect from 'react';
import connect from 'react-redux';
const MessagingComponent = React.memo(( loadMessages, messages, ...props ) =>
useEffect(() =>
loadMessages();
);
return <div ...props>These are the messages</div>;
);
const mapDispatchToProps = dispatch => (
loadMessages: () => dispatch( type: 'LOAD_MESSAGES' )
);
const mapStateToProps = state =>
return
messages: state.chatt.messages.chatMessages
;
;
export default connect(
mapStateToProps,
mapDispatchToProps
)(MessagingComponent);
如你所见,我在MessagingComponent
的useEffect()
回调中调用了loadMessages()
函数的效果回调:
useEffect(() =>
loadMessages();
);
对loadMessages()
的调用会加载导致组件重新渲染的消息。这种行为符合预期,但问题是重新渲染会导致useEffect()
钩子再次触发,从而导致loadMessages()
再次被调用。这反过来从后端加载消息并导致组件再次呈现,并且循环重复。
我怎样才能避免这种情况?我应该在useEffect()
钩子中简单地放置一个 if 条件,然后检查 messages 属性吗?
【问题讨论】:
【参考方案1】:如果我理解正确,您想通过useEffect()
模仿基于常规类的 React 组件的“组件安装”行为,以便效果回调仅在第一次渲染时触发一次。
要实现该行为,您可以将一个空数组传递给useEffect()
的第二个参数,如下所示:
useEffect(() =>
loadMessages();
, []); /* <-- add this */
第二个数组参数允许您指定哪些prop
变量在其值更改时触发useEffect()
回调(如果有)。
通过传递一个空数组,这意味着useEffect()
不会被输入prop
变量的任何更改触发,并且只会在第一次渲染期间被调用一次。
有关第二个参数的更多信息,see this documentation 和 this documentation
【讨论】:
这会导致警告:React Hook useEffect has missing dependencies: loadMessages Either include them or remove the dependency array react-hooks/exhaustive-deps
如何处理警告?我们应该离开它吗?我正在使用 redux thunk 并执行 props.loadMessages() 并警告说 props 是缺少的依赖项。在这种情况下该怎么办?谢谢
要摆脱警告,您可以将您的函数添加到依赖数组中,如下所示:useEffect(() => loadMessages(); , [loadMessages]);
。当您提供一系列依赖项时,您的效果将仅在其中一个依赖项发生更改时运行。因此,只有当您的 loadMessage
函数发生更改时,您的效果才会再次运行,这可能不会发生。
@alextouzel 在 deps 数组中添加函数会导致无限循环
@GianlucaPietrobon 如果loadMessages
函数引用没有改变,它不会导致无限循环。默认情况下 mapDispatchToProps 只被调用一次(当你的组件实例被创建时),所以在这种情况下,函数引用应该保持不变,并且 useEffect 挂钩只会运行一次,即使它的依赖项中有loadMessages
。【参考方案2】:
useEffect()
是一个功能组件的反应钩子,它涵盖了类组件的生命周期钩子的功能。 useEffect()
结合了类组件的componentDidMount(), componentDidUpdate()
和componentWillUnmount()
,这意味着它会在组件被挂载、组件状态改变以及组件从DOM中卸载时执行。
查看以下示例,
useEffect(() =>
setTimeout(() =>
alert("data saved");
, 1000);
);
当组件被挂载/初始渲染、组件状态发生变化以及组件从 DOM 中卸载时,将执行上述代码/警报。
为了减少上述代码的运行频率,我们可以传递一个值数组作为第二个参数,作为该效果的依赖项。如果其中一个依赖项发生变化,效果将再次运行。
假设我们将 people 数组传递到功能组件的 props 中,并且我们希望仅在 people 数组更改时才执行警报。
useEffect(() =>
setTimeout(() =>
alert("data saved");
, 1000);
, [props.persons]);
这将在初始渲染期间和props.persons
更改时执行代码。
所以要仅在初始渲染/组件挂载期间执行代码,您可以传递一个空数组,这意味着在执行效果时没有指定依赖项。因此在初始渲染和组件卸载时运行。
useEffect(() =>
setTimeout(() =>
alert("data saved");
, 1000);
, []);
你可以修改你的useEffect()
钩子如下,只调用一次来获取API数据,
useEffect(() =>
loadMessages();
, []);
【讨论】:
以上是关于ReactJS:如何只调用一次 useEffect 挂钩来获取 API 数据的主要内容,如果未能解决你的问题,请参考以下文章
ReactJs/NextJs useEffect() 总是被调用两次
如何使用/不使用 useEffect 钩子在 React JS 函数中获取更改的(新)状态值?
如何从 Reactjs 中的 useEffect 挂钩访问道具