Passing an empty array as the second argument to useEffect makes it only run on mount and unmount, thus stopping any infinite loops.

useEffect(() => {
  setIngredients({});
}, []);

This was clarified to me in the blog post on React hooks at https://www.robinwieruch.de/react-hooks/

Answer from WhiteFluffy on Stack Overflow
Top answer
1 of 16
231

Passing an empty array as the second argument to useEffect makes it only run on mount and unmount, thus stopping any infinite loops.

useEffect(() => {
  setIngredients({});
}, []);

This was clarified to me in the blog post on React hooks at https://www.robinwieruch.de/react-hooks/

2 of 16
135

Had the same problem. I don't know why they not mention this in docs. Just want to add a little to Tobias Haugen answer.

To run in every component/parent rerender you need to use:

  useEffect(() => {

    // don't know where it can be used :/
  })

To run anything only one time after component mount(will be rendered once) you need to use:

  useEffect(() => {

    // do anything only one time if you pass empty array []
    // keep in mind, that component will be rendered one time (with default values) before we get here
  }, [] )

To run anything one time on component mount and on data/data2 change:

  const [data, setData] = useState(false)
  const [data2, setData2] = useState('default value for first render')
  useEffect(() => {

// if you pass some variable, than component will rerender after component mount one time and second time if this(in my case data or data2) is changed
// if your data is object and you want to trigger this when property of object changed, clone object like this let clone = JSON.parse(JSON.stringify(data)), change it clone.prop = 2 and setData(clone).
// if you do like this 'data.prop=2' without cloning useEffect will not be triggered, because link to data object in momory doesn't changed, even if object changed (as i understand this)
  }, [data, data2] )

How i use it most of the time:

export default function Book({id}) { 
  const [book, bookSet] = useState(false) 

  const loadBookFromServer = useCallback(async () => {
    let response = await fetch('api/book/' + id)
    response  = await response.json() 
    bookSet(response)
  }, [id]) // every time id changed, new book will be loaded

  useEffect(() => {
    loadBookFromServer()
  }, [loadBookFromServer]) // useEffect will run once and when id changes


  if (!book) return false //first render, when useEffect did't triggered yet we will return false

  return <div>{JSON.stringify(book)}</div>  
}
🌐
DEV Community
dev.to › oyedeletemitope › three-ways-to-cause-infinite-loops-when-using-useeffect-in-react-and-how-to-prevent-them-3ip3
Three Ways to Cause Infinite Loops When Using UseEffect in React and How to Prevent Them - DEV Community
November 17, 2024 - Since there's no dependency check, the useEffect hook will also run again after the re-render. This cycle of state update triggering re-render, which in turn triggers useEffect again, will continue indefinitely, causing the infinite loop.
Discussions

useEffect causes an infinite loop?
TL;DR) Add [] as a second argument to useEffect useEffect() with no second argument will run every render. This means every time the request completes and you force a rerender by calling setItems, you will issue another request. The solution to this is the use the optional second argument to useEffect known as the dependency list. This will make it only trigger when that deps list changes. You can use an empty argument if your fetch is based on nothing []. If it changes then you can add any immutable types to that list. useEffect(() => { sanityClient .fetch( `*[_type == "issue"] | order(publishedAt desc) { title, slug, description, frontCover{ asset->{ _id, url } } }` ) .then((data) => { setItems(data); }) .catch(console.error); }, []); See the very last line that I changed above ^ See more on the official docs for useEffect https://beta.reactjs.org/reference/react/useEffect A side note, you may want to hoist your fetch method up to make it easier to read your code like so: const fetchSanity = () => sanityClient .fetch( `*[_type == "issue"] | order(publishedAt desc) { title, slug, description, frontCover{ asset->{ _id, url } } }` ) More on reddit.com
🌐 r/reactjs
16
0
January 21, 2023
Infinite loop in useEffect using blank object or array
Using React Version: 16.8.4 When using blank object or array as a setter for function inside useEffect does cause infinite loop. However using string or number does not trigger this. Here's the min... More on github.com
🌐 github.com
8
March 13, 2019
reactjs - Passing a function in the useEffect dependency array causes infinite loop - Stack Overflow
Why is an infinite loop created when I pass a function expression into the useEffect dependency array? The function expression does not alter the component state, it only references it. // componen... More on stackoverflow.com
🌐 stackoverflow.com
reactjs - useEffect runs infinite loop despite no change in dependencies - Stack Overflow
However, despite adding the data variable as a dependency, useEffect still fires on an infinite loop - even though the data hasn't changed. How can I stop useEffect from firing continuously? I've tried the empty array hack, which DOES stop useEffect from continuously firing, but it's not the ... More on stackoverflow.com
🌐 stackoverflow.com
People also ask

Why is the dependency array important in useEffect?
The dependency array tells React when to run the effect, ensuring it runs only when necessary and preventing continuous re-renders.
🌐
dhiwise.com
dhiwise.com › blog › design-converter › preventing-react-useeffect-infinite-loop-simple-fixes
React UseEffect Infinite Loop: Common Causes and Solutions
What causes infinite loops in useEffect?
Infinite loops occur when useEffect runs on every render, often due to missing or incorrect dependency arrays or state updates inside the effect.
🌐
dhiwise.com
dhiwise.com › blog › design-converter › preventing-react-useeffect-infinite-loop-simple-fixes
React UseEffect Infinite Loop: Common Causes and Solutions
How can I prevent an infinite loop in useEffect?
Use a proper dependency array, memoize functions and objects with useCallback or useMemo, and avoid unnecessary state updates within the effect.
🌐
dhiwise.com
dhiwise.com › blog › design-converter › preventing-react-useeffect-infinite-loop-simple-fixes
React UseEffect Infinite Loop: Common Causes and Solutions
🌐
GitHub
github.com › facebook › react › issues › 18243
Bug: Passing an array as a `useEffect` dependency causes an infinite loop · Issue #18243 · facebook/react
March 7, 2020 - Notice in the code above, that I don't even use or modify args at all, in the useEffect callback. If I change the value of args to a string, like const args = 'a', then there is no endless loop. So the problem seems to occur when the dependency is an array. The page runs in an infinite loop.
Author   garyking
🌐
LogRocket
blog.logrocket.com › home › how to solve the react useeffect hook’s infinite loop patterns
How to solve the React useEffect Hook's infinite loop patterns - LogRocket Blog
June 4, 2024 - Furthermore, notice that we passed the count Hook to its dependency array as well · This means that every time the value of count updates, React invokes useEffect · As a result, the useEffect Hook invokes setCount, thus updating count again ...
🌐
Max Rozen
maxrozen.com › learn-useeffect-dependency-array-react-hooks
Preventing infinite re-renders when using useEffect and useState - Max Rozen
Changing state will always cause a re-render. By default, useEffect always runs after render has run. This means if you don't include a dependency array when using useEffect to fetch data, and use useState to display it, you will always trigger ...
🌐
Dmitri Pavlutin
dmitripavlutin.com › react-useeffect-infinite-loop
How to Solve the Infinite Loop of React.useEffect()
February 26, 2023 - The infinite loop is fixed with correct management of the useEffect(callback, dependencies) dependencies argument.
🌐
Reddit
reddit.com › r/reactjs › useeffect causes an infinite loop?
r/reactjs on Reddit: useEffect causes an infinite loop?
January 21, 2023 -

Hey!! First time building a website and have ran into this issue when trying to fetch content from Sanity Studio.

Here's the link: https://pastebin.com/3iL0gpBt

Copying what I think is the relevant part of the code

export default function IssuesList() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    sanityClient
      .fetch(
        `*[_type == "issue"] | order(publishedAt desc) {
      title,
      slug,
      description,
      frontCover{
        asset->{
          _id,
          url
        }
      }
    }`
      )
      .then((data) => {
        setItems(data);
      })
      .catch(console.error);
  });

  return (
    <div css={issuesListSx}>
      <Frame path={[{ name: "Issues", slug: "/issues" }]}>
        <Grid gap={2} columns={[1, null, 2]} className="issuesGrid">
          {items.map((issue) => {
            return (
              <div className="issueItem" key={issue.title}>
                <Link to={"/issues/" + issue.slug.current}>
                  <div>{issue.title}</div>
                  {issue.frontCover && "asset" in issue.frontCover && (
                    <img src={issue.frontCover.asset.url} alt="" />
                  )}
                </Link>
              </div>
            );
          })}
        </Grid>
      </Frame>
    </div>
  );
}

E: Fixed!! Had to add an empty array as a second parameter to useEffect

Find elsewhere
🌐
freeCodeCamp
freecodecamp.org › news › prevent-infinite-loops-when-using-useeffect-in-reactjs
How to Prevent Infinite Loops When Using useEffect() in ReactJS
April 26, 2023 - So, similar to using useEffect, we can use an empty dependency array to ensure the function isn't being re-created between renders. This prevents the effect from running in an infinite loop when a function is used as a dependency.
🌐
CodingDeft
codingdeft.com › posts › react-useeffect-infinite-loop
How to solve Infinity loop in React's useEffect | CodingDeft.com
Tutorial on how to fix infinite loop in useEffect using dependency array, useMemo, and useCallback.
🌐
DhiWise
dhiwise.com › blog › design-converter › preventing-react-useeffect-infinite-loop-simple-fixes
React UseEffect Infinite Loop: Common Causes and Solutions
March 20, 2025 - A correct dependency array ensures ... Inside the Effect: Using setState within the effect causes a re-render, which triggers the effect again, leading to an infinite loop if not controlled properly....
🌐
GitHub
github.com › facebook › react › issues › 15096
Infinite loop in useEffect using blank object or array · Issue #15096 · facebook/react
March 13, 2019 - function Example() { const [count, setCount] = useState(0); const [foo, setFoo] = useState({}); useEffect(() => { console.log("Infinite Loop"); setCount(100); // doesn't cause infinite loop. // but this does // setFoo({}); // or setFoo([]); }); return <div />; } I don't know if it's a bug or default behaviour because in earlier version of react (in v16.7.0-alpha.0), both string and number also causing infinite loop which seems to be fixed in latest one.
Author   eashish93
🌐
Perficient Blogs
blogs.perficient.com › 2024 › 12 › 16 › avoiding infinite loops when utilizing useeffect() in reactjs
Avoiding Infinite Loops When Utilizing useEffect() in ReactJS / Blogs / Perficient
December 16, 2024 - Even though the content of data remains the same, its reference changes with each render. As a result, the useEffect hook will be triggered on every render, leading to an infinite loop of state updates and re-renders.
🌐
Plain English
plainenglish.io › blog › 5-useeffect-infinite-loop-patterns-2dc9d45a253f
5 useEffect Infinite Loop Patterns
July 23, 2021 - To fix this issue, we need to use ... know, the shallow comparison for two is always false, so passing dependencies as an array will also lead to Infinite Loop....
Top answer
1 of 3
112

The issue is that upon each render cycle, markup is redefined. React uses shallow object comparison to determine if a value updated or not. Each render cycle markup has a different reference. You can use useCallback to memoize the function though so the reference is stable. Do you have the react hook rules enabled for your linter? If you did then it would likely flag it, tell you why, and make this suggestion to resolve the reference issue.

const markup = useCallback(
  (count) => {
    const stringCountCorrection = count + 1;
    return (
      // Some markup that references the sections prop
    );
  },
  [/* any dependencies the react linter suggests */]
);

// No infinite looping, markup reference is stable/memoized
useEffect(() => {
  if (sections.length) {
    const sectionsWithMarkup = sections.map((section, index) => markup(index));
    setSectionBlocks(blocks => [...blocks, ...sectionsWithMarkup]);
  } else {
    setSectionBlocks([]);
  }
}, [sections, markup]);

Alternatively if the markup function is only used in the useEffect hook you can move it directly into the hook callback to remove it as an external dependency for the hook.

Example:

useEffect(() => {
  const markup = (count) => {
    const stringCountCorrection = count + 1;
    return (
      // Some markup that references the sections prop
    );
  };

  if (sections.length) {
    const sectionsWithMarkup = sections.map((section, index) => markup(index));
    setSectionBlocks(blocks => [...blocks, ...sectionsWithMarkup]);
  } else {
    setSectionBlocks([]);
  }
}, [sections, /* any other dependencies the react linter suggests */]);

Additionally, if the markup function has absolutely no external dependencies, i.e. it is a pure function, then it could/should be declared outside any React component.

2 of 3
9

Why is an infinite loop created when I pass a function expression

The "infinite loop" is the component re-rendering over and over because the markup function is a NEW function reference (pointer in memory) each time the component renders and useEffect triggers the re-render because it's a dependency.

The solution is as @drew-reese pointed out, use the useCallback hook to define your markup function.

🌐
GeeksforGeeks
geeksforgeeks.org › how-to-avoid-infinite-loops-when-using-useeffect-in-reactjs
How To Avoid Infinite Loops When Using useEffect() in ReactJS? | GeeksforGeeks
October 14, 2024 - If we didn't specify any dependencies, the hook would be called after every render, causing an infinite loop. By specifying the empty array as the dependency, we ensure that the hook is only called once, and we avoid any performance issues or ...
🌐
DEV Community
dev.to › collegewap › how-to-solve-infinity-loop-in-reacts-useeffect-5d6e
How to solve Infinity loop in React's useEffect? - DEV Community
March 28, 2023 - In the above code, we are calling setCounter inside the useEffect hook and the counter increments. As the state changes, the component gets re-rendered and useEffect runs again and the loop continues. The useEffect hook runs again as we did not pass any dependency array to it and causes an infinite loop.
🌐
w3tutorials
w3tutorials.net › blog › passing-array-to-useeffect-dependency-list
React useEffect Array Dependency: How to Avoid Infinite Loops and Dispatch Actions on Changes — w3tutorials.net
However, its behavior is tightly ... controls when the effect runs. Mismanaging this array can lead to frustrating issues like infinite re-render loops, stale data, or unnecessary side effects....
Top answer
1 of 4
40

The way the useEffect dependency array works is by checking for strict (===) equivalency between all of the items in the array from the previous render and the new render. Therefore, putting an array into your useEffect dependency array is extremely hairy because array comparison with === checks equivalency by reference not by contents.

const foo = [1, 2, 3];
const bar = foo;
foo === bar; // true

const foo = [1, 2, 3];
const bar = [1, 2, 3];
foo === bar; // false

Inside of your effect function, when you do setInvoiceData(results) you are updating invoiceData to a new array. Even if all the items inside of that new array are exactly the same, the reference to the new invoiceData array has changed, causing the dependencies of the effect to differ, triggering the function again -- ad infinitum.

One simple solution is to simply remove invoiceData from the dependency array. In this way, the useEffect function basically acts similar to componentDidMount in that it will trigger once and only once when the component first renders.

useEffect(() => {
    const updateInvoiceData = async () => {
      const results = await api.invoice.findData();
      setInvoiceData(results);
    };
    updateInvoiceData();
  }, []);

This pattern is so common (and useful) that it is even mentioned in the official React Hooks API 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.

2 of 4
3

Credit to jered for the great "under the hood" explanation; I also found Milind's suggestion to separate out the update method from useEffect to be particularly fruitful. My solution, truncated for brevity, is as follows -

const Invoices = () => {
  const [invoiceData, setInvoiceData] = useState([]);

  useEffect(() => {    
    updateInvoiceData();
  }, []);

  // Extracting this method made it accessible for context/prop-drilling
  const updateInvoiceData = async () => {
    const results = await api.invoice.findData();
    setInvoiceData(results);
  };

  return (
    <div>
      <OtherComponentThatUpdatesData handleUpdateState={updateInvoiceData} />
      <Table entries={invoiceData} />
    </div>
  );
};
🌐
Reddit
reddit.com › r › reactjs › comments › 11pabq8 › useeffect_dependencies_causing_a_infinite_loop_of
UseEffect Dependencies causing a infinite loop of ...
March 12, 2023 - For my external UseEffect function, esLinter keeps on saying I am missing dependencies in the array for the second argument namely: [urlArray, setFunctArray, getLocationPromise, location] However as soon as I add either the urlArray, or setFunctArray . I searched and found this stackoverFlow post that says that to handle arrays in the dependency array you need to use JSON.stringify(array). This stops the infinite loop ...