You can pass JSON.stringify(outcomes) as the dependency list:

Read more here

useEffect(() => {
  console.log(outcomes)
}, [JSON.stringify(outcomes)])
Answer from Loi Nguyen Huynh on Stack Overflow
Top answer
1 of 7
195

You can pass JSON.stringify(outcomes) as the dependency list:

Read more here

useEffect(() => {
  console.log(outcomes)
}, [JSON.stringify(outcomes)])
2 of 7
23

Using JSON.stringify() or any deep comparison methods may be inefficient, if you know ahead the shape of the object, you can write your own effect hook that triggers the callback based on the result of your custom equality function.

useEffect works by checking if each value in the dependency array is the same instance with the one in the previous render and executes the callback if one of them is not. So we just need to keep the instance of the data we're interested in using useRef and only assign a new one if the custom equality check return false to trigger the effect.

function arrayEqual(a1: any[], a2: any[]) {
  if (a1.length !== a2.length) return false;
  for (let i = 0; i < a1.length; i++) {
    if (a1[i] !== a2[i]) {
      return false;
    }
  }
  return true;
}

type MaybeCleanUpFn = void | (() => void);

function useNumberArrayEffect(cb: () => MaybeCleanUpFn, deps: number[]) {
  const ref = useRef<number[]>(deps);

  if (!arrayEqual(deps, ref.current)) {
    ref.current = deps;
  }

  useEffect(cb, [ref.current]);
}

Usage

function Child({ arr }: { arr: number[] }) {
  useNumberArrayEffect(() => {
    console.log("run effect", JSON.stringify(arr));
  }, arr);

  return <pre>{JSON.stringify(arr)}</pre>;
}

Taking one step further, we can also reuse the hook by creating an effect hook that accepts a custom equality function.

type MaybeCleanUpFn = void | (() => void);
type EqualityFn = (a: DependencyList, b: DependencyList) => boolean;

function useCustomEffect(
  cb: () => MaybeCleanUpFn,
  deps: DependencyList,
  equal?: EqualityFn
) {
  const ref = useRef<DependencyList>(deps);

  if (!equal || !equal(deps, ref.current)) {
    ref.current = deps;
  }

  useEffect(cb, [ref.current]);
}

Usage

useCustomEffect(
  () => {
    console.log("run custom effect", JSON.stringify(arr));
  },
  [arr],
  (a, b) => arrayEqual(a[0], b[0])
);

Live Demo

Discussions

javascript - How to use useEffect hook with the dependency list as a specific field in an array of objects? - Stack Overflow
I don't think you can specifically tackle it in the dependency array, however, you can do your check inside the useEffect to have the same overall outcome. Basically, the dependency array is passed the full data state, which will trigger the effect every change, then you do a further check ... More on stackoverflow.com
🌐 stackoverflow.com
November 18, 2021
reactjs - useEffect and dependency array - Stack Overflow
useEffect will re-run with an object in it's dependency array whenever that object changes references. More on stackoverflow.com
🌐 stackoverflow.com
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
You can't use objects or arrays in useEffect?
State variables are "memorized" between renders (same as refs*) so you can use them. Arrays and objects, as you correctly understood, will be compared by reference so you have to memorize them (ref, state or useMemo). Though there is an alternative options (more so for objects than arrays but for "tuple arrays" it could still make sense) that you just add it to the dependency array in a destructed fashion. You might even find that you don't need all fields, just some. *Just remember that useEffect is tied to renders and changing a ref does not guarantee a re-render so it also does not guarantee a re-run of the useEffect even if you include it into the dependency array (it will run but only after something else triggers the render). More on reddit.com
🌐 r/reactjs
16
1
November 5, 2023
People also ask

Can you use objects or arrays in the useEffect dependency array?
Yes, but JavaScript compares object or array references, not their contents. This can cause unnecessary re-renders. To avoid this, use the useMemo hook to memoize objects or arrays used in the dependency array.
🌐
dhiwise.com
dhiwise.com › post › understanding-the-importance-of-the-useeffect-dependency-array-in-react
UseEffect Dependency Array
Why is the dependency array important in useEffect?
The dependency array in useEffect tells React when to re-run the effect. It ensures the effect only runs when specified state or prop values change, improving performance and avoiding unnecessary renders.
🌐
dhiwise.com
dhiwise.com › post › understanding-the-importance-of-the-useeffect-dependency-array-in-react
UseEffect Dependency Array
What happens if you don’t pass a dependency array to useEffect?
Without a dependency array, the effect runs after every render. This can lead to performance issues and bugs since the effect won't re-run based on changes in specific dependencies.
🌐
dhiwise.com
dhiwise.com › post › understanding-the-importance-of-the-useeffect-dependency-array-in-react
UseEffect Dependency Array
🌐
Reddit
reddit.com › r/reactjs › passing array to useeffect dependency list
r/reactjs on Reddit: Passing array to useEffect dependency list
August 21, 2019 -

I'm having an issue with useEffect not firing if an array in the dependency list changes.

//props.shapes = ['stuff', 'in', 'the', 'array']
useEffect(() => {
   // do stuff
  }, [props.shapes])

Nothing in that useEffect runs. This...should work right? If the array changes higher up in the component tree a new array is generated and that should trigger a re-render in this component and then the useEffect will fire, right?

What's weird is if I make it dependent on the length, it does work

//props.shapes = ['stuff', 'in', 'the', 'array']
useEffect(() => {
   // do stuff
  }, [props.shapes.length])

My gut tells me that this array is actually getting mutated somewhere and that is causing the issue...but I don't see that in the app. What am I fundamentally misunderstanding about arrays (and I guess objects) with useEffect?

Ninja Edit: I know that using .length in the array dependency will lead to bugs if the array values change but the length doesn't. I don't plan on using this, just explaining what I'm experiencing.

🌐
React
react.dev › reference › react › useEffect
useEffect – React
To connect your component to some external system, call useEffect at the top level of your component: ... A setup function with setup code that connects to that system. It should return a cleanup function with cleanup code that disconnects from that system. A list of dependencies including every value from your component used inside of those functions.
🌐
DhiWise
dhiwise.com › post › understanding-the-importance-of-the-useeffect-dependency-array-in-react
UseEffect Dependency Array
August 13, 2025 - This blog provides a clear, structured ... strategies to help your components work as intended. The dependency array is the second parameter you pass to the useEffect hook....
🌐
Medium
medium.com › @joabi › react-patterns-optimization-of-dependency-array-in-useeffect-b551d172fc76
React Patterns: Optimization of Dependency Array in useEffect | by Julie J. | Medium
November 4, 2023 - This is because React uses a concept called “referential equality” when it comes to objects in the dependency array. What this means is that we can’t be sure if the object’s reference will remain the same between re-renders. So, even if the content inside the object hasn’t changed, React may still think it’s a different object and trigger the effect to run again. Our goal should be to reduce how often the object’s reference changes. import { useEffect, useState } from "react"; function Expense(props) { useEffect(() => { console.log("Run effect when date changed"); }, [props.date]
Find elsewhere
🌐
egghead.io
egghead.io › lessons › react-manage-the-useeffect-dependency-array
Manage the useEffect dependency array | egghead.io
[0:54] React useEffect accepts a second argument as an optimization to combat this problem. That second argument is a dependency array where you pass all the dependencies for your side effect.
Published   March 10, 2020
🌐
Medium
medium.com › devil-is-in-the-details › dependency-array-in-useeffect-hook-d73e0ef2ab33
Dependency array in useEffect hook | by Shreejit Rajbanshi | Devil is in the Details | Medium
November 20, 2022 - This might be the most common form used with useEffect. We pass an array filled with all the dependencies that should trigger the callback function to run. Change in any of the variable in the list will execute the callback.
🌐
Retool
retool.com › blog › hooks-and-state-102-the-dependency-array-in-useeffect
Hooks and state 102: the Dependency array in useEffect()
July 9, 2025 - The correct solution here is to use `isDesktop` and `selectedPatient` to initialize component state variables. Whenever `selectedPatient` changes, the first useEffect will update both states with the passed-in props, ...
🌐
Zipy
zipy.ai › blog › react-useeffect-dependency-array
React useEffect Dependency Array Guide
May 23, 2024 - The component's state can be updated or side effects can be carried out using this function. Passing an empty array as the dependent parameter for the useEffect hook in React is one of the easiest ways to use it.
🌐
GitHub
gist.github.com › msubhan9803 › 8a8e4fe91628635c6c84c627affa16d1
Passing array to useEffect dependency list · GitHub
Passing array to useEffect dependency list. GitHub Gist: instantly share code, notes, and snippets.
🌐
Bitstack
blog.bitsrc.io › understanding-dependencies-in-useeffect-7afd4df37c96
Understanding Dependencies in useEffect | Bits and Pieces
March 4, 2025 - The effect runs after any of these values changes (and after the initial render). The array of dependencies is not passed as argument to the effect function. The last point is important.
🌐
The Web Dev
thewebdev.info › home › how to pass an array to useeffect dependency list in react?
How to pass an array to useEffect dependency list in React? - The Web Dev
November 14, 2021 - Then we call useEffect with a callback that logs the current value of nums. We watch the value of the nums array by passing it into the dependencies array.
🌐
Ben Ilegbodu
benmvp.com › blog › object-array-dependencies-react-useEffect-hook
Object & array dependencies in the React useEffect Hook | Ben Ilegbodu
January 2, 2021 - I've already discussed dealing ... we have when dealing with objects or arrays as useEffect dependencies. In this first problem, let's say we have an object being passed in as a prop that we're also using in the dependencies list of useEffect....
Top answer
1 of 3
5

useEffect will re-run with an object in it's dependency array whenever that object changes references.

For example in your code, user is always stable until you call setUser in which case it will change to a new reference and run at that point.

If you instead defined user as a new object in each render, then the useEffect would instead run every time the component re-rendered.

  const user = {
    firstName: 'Joe',
    lastName: 'Smith',
    address: {
      home: '123 street',
    },
  };

It's all about referential equality. Whether previousUser===newUser on each render. React essentially performs a check very similar to that (I believe Object.is) for every variable in the dependency array.

2 of 3
1

Bellow your component.

changes:

  • move initialState outside UseEffectHook. You don't need to create initialState every re-render;
  • use useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed;
  • setUser and setCount with updater function;
  • handleOnChangeUser able to use for all fields of user object. Every time handleOnChangeUser - create new ref to user object. in this case useEffect able to detect changes;

import React, { useCallback, useEffect, useState } from 'react';

const initialState = {
  firstName: "Joe",
  lastName: "Smith",
  address: {
    home: "123 street",
  }
};

export function UseEffectHook() {
  const [user, setUser] = useState(initialState);
  const [count, setCount] = useState(0);
  const handleOnChangeUser = useCallback((event) => {
    const { name, value } = event;
    
    setUser(prevState => ({ ...prevState, [name]: value }));
  }, []);
  
  const increaseCount = useCallback(() => {
    setCount(prevState => prevState + 1);
  }, []);

  useEffect(() => {
    console.log("triggered");
  }, [user]);

  return (
    <div>
      <p>useEffect - Practice with different deps</p>
      {JSON.stringify(user)}

      <label>
        <span>Firstname:</span>

        <input
          type="text"
          name="firstName"
          onChange={handleOnChangeUser}
        />
      </label>
      
      <br />
      
      <label>
        <span>Lastname:</span>
        
        <input
          type="text"
          name="lastName"
          onChange={handleOnChangeUser}
        />
      </label>

      <button onClick={increaseCount}>Increase</button>
   </div>
  );
}

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.

🌐
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
Mismanaging this array can lead to frustrating issues like infinite re-render loops, stale data, or unnecessary side effects. In this blog, we’ll demystify the useEffect dependency array, explore why infinite loops occur, and learn how to safely dispatch actions (e.g., Redux, Context API) when dependencies change.
🌐
Reddit
reddit.com › r/reactjs › you can't use objects or arrays in useeffect?
r/reactjs on Reddit: You can't use objects or arrays in useEffect?
November 5, 2023 -

Specifically, inside the dependency array. I've scoured the docs to find an answer to this question but couldn't find anything. Even read Dan Abramov's long guide to useEffect and still couldn't figure it out.

Is it true that, since 1) rerenders recreate objects/arrays that are declared inside your component 2) the dependency array compares objects by reference, not by value, that if you put an object inside a useEffect dependency array it'll run every time?

If so, what about if I memoize the object with useMemo? Also, what about state variables? Does React check a useState value differently than if you declare something inside the component?

If anyone can help me understand this better, even if it's just linking to a specific part of the docs, I'd appreciate it a lot.

🌐
DEV Community
dev.to › hey_yogini › useeffect-dependency-array-and-object-comparison-45el
UseEffect dependency array and object comparison! - DEV Community
January 5, 2022 - Please let me know how you solved the problem while passing objects to the dependency array? And of course, thoughts/comments/feedback on the article :) You can also connect with me on Twitter or buy me a coffee if you like my articles. ... How is this different from putting the same in the dependency array? We can still put the same three properties like so · useEffect(() => { if (username) { // Do something…!