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);

如你所见,我在MessagingComponentuseEffect() 回调中调用了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(() =&gt; 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中使用上下文值,只运行一次

如何使用/不使用 useEffect 钩子在 React JS 函数中获取更改的(新)状态值?

如何从 Reactjs 中的 useEffect 挂钩访问道具

删除组件后如何清理react js中的useEffect函数

React useEffect 调用 API 的时间太多,当我的组件渲染时,如何将 API 调用限制为一次?