【问题标题】:ReactJS: how to call useEffect hook only once to fetch API dataReactJS:如何只调用一次 useEffect 挂钩来获取 API 数据
【发布时间】: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 属性吗?

【问题讨论】:

    标签: reactjs redux react-hooks


    【解决方案1】:

    如果我理解正确,您想通过useEffect() 模仿基于常规类的 React 组件的“组件安装”行为,以便效果回调仅在第一次渲染时触发一次。

    要实现该行为,您可以将一个空数组传递给useEffect() 的第二个参数,如下所示:

    useEffect(() => {
      loadMessages();
    }, []); /* <-- add this */
    

    第二个数组参数允许您指定哪些prop 变量在其值更改时触发useEffect() 回调(如果有)。

    通过传递一个空数组,这意味着useEffect() 不会被输入prop 变量的任何更改触发,并且只会在第一次渲染期间被调用一次。

    有关第二个参数的更多信息,see this documentationthis 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();
      }, []);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-28
      • 2022-01-16
      • 1970-01-01
      • 2021-10-09
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      相关资源
      最近更新 更多