Home > Net >  How do I avoid an infinite loop in useEffect when using Typescript?
How do I avoid an infinite loop in useEffect when using Typescript?

Time:10-17

I'm sending a request like this:

function getDecks() {
    return Axious.get(urlGetAllDecks).then((response) => response.data);
}

I'm then using a functional component, where I try to initialize the state by calling the above function from my database.js file. However, the useEffect block is called countless times.

export interface DeckSelectionState {
  id: number;
  module: number;
  title: string;
  description: string;
  dateCreated: string;
  reviewStatus: number;
  nextReviewDate: string;
}

const DeckSelection: React.FunctionComponent = () => {
  const [decks, setDecks] = React.useState<DeckSelectionState[]>([]);

  React.useEffect(() => {
    database.getDecks().then((response) => {
      setDecks(response);
    });
  });

Any idea on how to fix this?

CodePudding user response:

In order to make sure that the useEffect is only executed once, you must specify an appropriate dependency list by passing an array containing the values that the effect depend on. In your case, specifying the array [setDecks] ensures that the effect is only executed if the function setDecks changes.

The code should look like the following:

React.useEffect(() => {
  database.getDecks().then((response) => {
    setDecks(response);
  });
}, [setDecks]);

The second parameter of useEffect is the dependencies array and it specifies the list of values that the effect depend on, which means that the effect will only be executed if one of those values change. By specifying the array [setDecks] you are basically saying that the effect only depends on the value of setDecks and should only be executed if that function changes, while not specifying the dependency array means that the effect depend on all props and state.

From the documentation:

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works. If you pass an empty array ([]), the props and state inside the effect will always have their initial values. While passing [] as the second argument is closer to the familiar componentDidMount and componentWillUnmount mental model, there are usually better solutions to avoid re-running effects too often. Also, don’t forget that React defers running useEffect until after the browser has painted, so doing extra work is less of a problem.

CodePudding user response:

React.useEffect(() => {
    database.getDecks().then((response) => {
      setDecks(response);
    }, [setDecks]);

To make useEffect run only once, you can pass an empty array as the second argument (dependency array for useEffect)

In this case you should put setDecks into the dependency array

  • Related