1

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?

1 Answer 1

4

In order to make sure that the useEffect is only executed once, you must specify an empty dependency list by passing an empty array.

The code should look like the following:

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

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 [] you are basically saying that the effect does not depend on any value and should only be executed once, 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.

Why not specify [setDecks] as the dependency array?

setDecks is the function for setting the state corresponding to the useState hook you have used. While you can add it to the dependency array as the effect seems to "depend" on it, it will never change, thus it will never impact the effect. From the documentation on useState:

React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.

Sign up to request clarification or add additional context in comments.

4 Comments

setDecks should go in the dependency array (but will not cause a re-render)
Thanks @jsejcksn. I missed that, I updated my answer.
You was correct with [], putting setDecks as a dependency is not doing anything here,.. decks maybe, but only if decks was used in running the effect, but in this case it wasn't.. @jsejcksn you might want to review what the dependency does,. I blame the Doc's here on React's site, as it seems to imply [] should never be used, but what the OP has posted the effect has no relation to any props or state..
Thank you @Keith for pointing that out. I got confused thinking that the setDecks was a prop that can change, I have updated my answer to explain why it is safe to omit it from the dependency list.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.