ReactJS:如何只调用一次 useEffect 钩子来获取 API 数据

IT技术 reactjs redux react-hooks
2021-04-05 20:32:17

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

如您所见,我有一个效果回调,它在我loadMessages()useEffect()回调中调用函数MessagingComponent

  useEffect(() => {
    loadMessages();
  });

调用loadMessages()加载消息导致组件重新渲染。这种行为符合预期,但问题是重新渲染会导致useEffect()钩子再次触发,从而导致loadMessages()再次调用。这反过来从后端加载消息并导致组件再次呈现,并且循环重复。

我怎样才能避免这种情况?我应该简单地在useEffect()钩子中放置一个 if 条件,并检查消息属性吗?

2个回答

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

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

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

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

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

有关第二个参数的更多信息,请参阅此文档此文档

@alextouzel 在 deps 数组中添加函数会导致无限循环
2021-05-22 20:32:17
收到警告怎么办?我们应该离开它吗?我正在使用 redux thunk 并执行 props.loadMessages() 并且警告是 props 是一个缺失的依赖项。这种情况怎么办?谢谢
2021-05-28 20:32:17
为了摆脱的警告,您可以将功能添加到依赖阵列,像这样:useEffect(() => { loadMessages(); }, [loadMessages]);当您提供一组依赖项时,您的效果只会在其中一个依赖项发生更改时运行。因此,如果您的loadMessage功能发生变化,您的效果只会再次运行,这可能不会发生。
2021-05-30 20:32:17
这会导致警告: React Hook useEffect has missing dependencies: loadMessages Either include them or remove the dependency array react-hooks/exhaustive-deps
2021-06-03 20:32:17
@GianlucaPietrobon 如果loadMessages函数引用不变,则不会导致无限循环。默认情况下,mapDispatchToProps 只被调用一次(当你的组件实例被创建时),所以在这种情况下,函数引用应该保持不变,并且 useEffect 钩子只会运行一次,即使它有loadMessages它的依赖项。
2021-06-12 20:32:17

useEffect()是功能组件的react-hooks,它涵盖了类组件的生命周期钩子的功能。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();
  }, []);