In this case, no, the useState setter function will never change, but useEffect doesn't know it is a function from another hook, it just sees a function.

Consider this use case:

const MyComponent = ({ onUpdate }) => {
  const [state, setState] = useState();
  useEffect(() => {
    // state updated, call onUpdate callback with state
    onUpdate(state);
  }, [onUpdate, state]);
  return ...
}

Now parent component can, given

<MyComponent onUpdate={onUpdateHandler} />

define onUpdateHandler as

let onUpdateHandler = console.log;

then later change it while still mounted

onUpdateHandler = state => dispatch({ type: 'SAVE_STATE', state });

By placing the callback in the dependency array the effect hook see the value of onUpdate changed and trigger the effect again. If it didn't include the callback then it would continue to console.log state updates instead of now handling it differently.

It is more likely for values to change than it is for functions to change, but function values can change. You likely have an eslinter that is recommending you add all the variables used within the hook to the dependency array, and this will in most cases be the correct thing to do. A few exceptions are for example, when you want an effect to compute ONLY when the component mounts by specifying an empty array, or not including some variables that are functions that you KNOW will never change during the life of the component, and in these cases you can use the eslint-disable-next-line react-hooks/exhaustive-deps override to unflag it as a warning. Caution though, as this will disable the linting checks so it is possible for bugs to creep in if not paying attention.

Answer from Drew Reese on Stack Overflow
Top answer
1 of 1
28

In this case, no, the useState setter function will never change, but useEffect doesn't know it is a function from another hook, it just sees a function.

Consider this use case:

const MyComponent = ({ onUpdate }) => {
  const [state, setState] = useState();
  useEffect(() => {
    // state updated, call onUpdate callback with state
    onUpdate(state);
  }, [onUpdate, state]);
  return ...
}

Now parent component can, given

<MyComponent onUpdate={onUpdateHandler} />

define onUpdateHandler as

let onUpdateHandler = console.log;

then later change it while still mounted

onUpdateHandler = state => dispatch({ type: 'SAVE_STATE', state });

By placing the callback in the dependency array the effect hook see the value of onUpdate changed and trigger the effect again. If it didn't include the callback then it would continue to console.log state updates instead of now handling it differently.

It is more likely for values to change than it is for functions to change, but function values can change. You likely have an eslinter that is recommending you add all the variables used within the hook to the dependency array, and this will in most cases be the correct thing to do. A few exceptions are for example, when you want an effect to compute ONLY when the component mounts by specifying an empty array, or not including some variables that are functions that you KNOW will never change during the life of the component, and in these cases you can use the eslint-disable-next-line react-hooks/exhaustive-deps override to unflag it as a warning. Caution though, as this will disable the linting checks so it is possible for bugs to creep in if not paying attention.

🌐
React
legacy.reactjs.org › docs › hooks-reference.html
Hooks API Reference – React
That way an effect is always recreated if one of its dependencies changes. However, this may be overkill in some cases, like the subscription example from the previous section. We don’t need to create a new subscription on every update, only if the source prop has changed. To implement this, pass a second argument to useEffect that is the array of values that the effect depends on.
Discussions

Do useEffects run if the component state doesn't change regardless of the dependencies they have been provided with?
[upd] I did not noticed that up to console.log useEffect is not called on 3rd re-render. Everything below still is valid, but has nothing to do with exact question "but why effect does not run at 3rd run?" each time component rerenders, useEffect strictly(think about it as ===, while actually, I believe, it's Object.is but in your case it does not matter) compares every dependency to previous value. Since argument arr is not passed to your hook, default value is used. Since default value defined inline, it's different each time. So on every rerender effect runs. To illustrate: function test(a = [1, 2]) { return a; } test() === test() // false or even easier: [1,2] === [1,2] // false More on reddit.com
🌐 r/reactjs
17
0
February 18, 2023
react.js - React setState function in useEffect - Code Review Stack Exchange
This means that you can include it in the useEffect dependencies with no problem. ... \$\begingroup\$ Thanks for the answer. Is this the best practice to do? Didn't see anything like this in the React docs. \$\endgroup\$ ... \$\begingroup\$ I would pass setExpanded as a dependency since according to the docs it's "free" for you to do so, but I think it would also be acceptable to pass an empty dependency array ... More on codereview.stackexchange.com
🌐 codereview.stackexchange.com
January 21, 2020
React useState hook with dependency - javascript
const [state, setState] = ... => setState(initialState), [initialState]); Cause from my understanding of React this is rendering the component twice when initialState changes: First to render its parent's children (due to initialState change). In this cycle, the useEffect update is added to the queue to be performed after rendering. and then a second type after the useEffect update has been performed. What I need is a dependency array on useState, ... More on stackoverflow.com
🌐 stackoverflow.com
Can someone explain useEffect dependency arrays like im 5?
Here are the three scenarios: 1- No dependency array >> code inside useEffect runs every time your component re-renders. 2- Empty dependency array >> code inside your useEffect only runs once when your component first mounts. 3- Not-empty dependency array >> code inside your useEffect runs every time any variables you put inside the dependency array change. The last part isn't exactly accurate. You components also needs to re-render. so if your put a state or a prob inside your dependency array, your component will re-render and the useEffect will run. However, if you put some kind of a const or locally defend variable that doesn't trigger a re-render when it's changed, the useEffect will only fire again with the next re-render. More on reddit.com
🌐 r/reactjs
24
34
April 24, 2022
🌐
GitHub
github.com › reactjs › react.dev › issues › 4506
The setState furnction from useState should be in the dependency array when called from within useEffect · Issue #4506 · reactjs/react.dev
March 28, 2022 - The setState furnction from useState should be in the dependency array when called from within useEffect#4506
Author   ellertsmari
🌐
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 another render after useEffect runs.
🌐
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 - Since `patients` is changed in useEffect, this creates an infinite re-render. You can tell React to skip unnecessarily rerunning the effect by specifying an array of dependencies as the second argument to the useEffect call.
🌐
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.
🌐
DEV Community
dev.to › catur › best-implement-setstate-on-useeffect-3je9
Best Implement setState on useEffect - DEV Community
October 21, 2022 - But notice again, that there is still a warning there (in the developer tools console): "React Hook useEffect has a missing dependency: 'state'. Either include it or remove the dependency array. You can also do a functional update 'setState(s => ...)' if you only need 'state' in the 'setState' call react-hooks/exhaustive-deps"
Find elsewhere
🌐
Atomizedobjects
atomizedobjects.com › blog › react › how-to-use-setstate-from-within-useeffect-with-dependencies
How to use setState from within useEffect | Atomized Objects
December 4, 2020 - Under the hood, what is happening is React is comparing each one of the dependencies in the array to the previous version of it from the last render. If the all versions are identical, then the variables will not be refreshed and the function will not be re-run. However, if any of the dependencies change between renders, then React will detect this, and then refresh all the variables and then run your function. Thankfully, using setState from within the useEffect dependency array couldn’t be simpler.
🌐
Zipy
zipy.ai › blog › react-useeffect-dependency-array
React useEffect Dependency Array Guide
May 23, 2024 - Learn to use useEffect dependency array, single & multiple state variable, empty dependency array, useEffect infinite loop, functions in dependency array,& more
🌐
Reddit
reddit.com › r/reactjs › do useeffects run if the component state doesn't change regardless of the dependencies they have been provided with?
r/reactjs on Reddit: Do useEffects run if the component state doesn't change regardless of the dependencies they have been provided with?
February 18, 2023 -

So I have this code:

import { useEffect, useState } from "react";

function useCounter(arr = [1, 2, 3, 4, 5]) {
    console.log("useCounter");
    const [counter, setCount] = useState(0);
    useEffect(() => {
        console.log("Effect");
        for (const i of arr) {
            setCount(i);
            console.log(counter);
        }
    }, [arr]);
}

function App() {
    console.log("____________________________________");
    useCounter();
    console.log("App");
    return <div className="App" />;
}

export default App;

It outputs this:

____________________________________
useCounter
App
Effect
0 (5 times)
____________________________________
useCounter
App
Effect
5 (5 times)
____________________________________
useCounter
App

Stuff going on with the first 2 rerenders is pretty straightforward and explainable (if not I will write it in a comment or edit this post writing my interpretation of what's going on) but what I couldn't wrap my head around is what's going on on the 3rd rerender.

So "useCounter" is getting logged because useCounter hook is being called then App is logged because it goes next (useEffect's callback is getting called right after the component renders something, so in this case it goes at the end), but useEffect's callback is not getting called even tho it's dependency (arr) was reestablished when useCounter was called and arr argument was assigned with a new instance of array [1,2,3,4,5] so it's a new array which is passed as a dependency to useEffect so it should run again right? causing an infinite loop of rerenders, but it doesn't, why is that happening? I have a guess that it somehow realizes that the previous counter and current counter gonna end up the same so no state changes and thus there is no point running useEffect's callback anymore despite dependency change but how is that happening without running the callback?

That question doesn't make me rest maybe react community could help me, please bring me peace at last

Top answer
1 of 5
3
[upd] I did not noticed that up to console.log useEffect is not called on 3rd re-render. Everything below still is valid, but has nothing to do with exact question "but why effect does not run at 3rd run?" each time component rerenders, useEffect strictly(think about it as ===, while actually, I believe, it's Object.is but in your case it does not matter) compares every dependency to previous value. Since argument arr is not passed to your hook, default value is used. Since default value defined inline, it's different each time. So on every rerender effect runs. To illustrate: function test(a = [1, 2]) { return a; } test() === test() // false or even easier: [1,2] === [1,2] // false
2 of 5
2
I got curious, so I tried to find out what was causing this. From the useState docs : If the new value you provide is identical to the current state, as determined by an Object.is comparison, React will skip re-rendering the component and its children. This is an optimization. Although in some cases React may still need to call your component before skipping the children, it shouldn’t affect your code. That last part seems to be what you're hitting. It seems concurrent mode does something but bails out of the render since the state is the same or something. I don't know why it needs to do it though. I also tried to add a child, and like the useEffect, it doesn't call it either. The behavior your seeing is exactly as described in the docs. Since you set the state to 5 two times, the second time it won't do an actual re-render. I'm also curios how you managed to code yourself into this, and got to the conclusion that react is the weird one.
🌐
DhiWise
dhiwise.com › post › understanding-the-importance-of-the-useeffect-dependency-array-in-react
UseEffect Dependency Array
August 13, 2025 - What is the Dependency Array in useEffectEmpty Dependency ArrayHow the Dependency Array Works in the Render CycleWhy You Get Missing Dependency WarningsCommon Dependency Array Mistakes and FixesEmpty Array vs No ArrayThe Role of Cleanup FunctionState Variables and Re RendersAdvanced: Functions ...
🌐
Reddit
reddit.com › r/reactjs › can someone explain useeffect dependency arrays like im 5?
r/reactjs on Reddit: Can someone explain useEffect dependency arrays like im 5?
April 24, 2022 -

When do you need to use it? Why do I need to put a empty array even though its empty? When would I put something in the empty array?

Sorry if stupid noob question.

🌐
React
react.dev › learn › removing-effect-dependencies
Removing Effect Dependencies – React
It is important to declare it as a dependency! This ensures, for example, that if the roomId changes, your Effect will re-connect to the chat with the new options. However, there is also a problem with the code above.
🌐
Codedamn
codedamn.com › news › react js
useEffect dependency array in React.js – Complete Guide
June 2, 2023 - The useEffect manages an array that contains the state variables or functions which are kept an eye for any changes. These changes then trigger the callback function. The most basic dependency array would be an empty array.
🌐
GitHub
github.com › facebook › react › issues › 23179
Bug: React Hooks eslint plugin reports i should add dependencies to useEffect which break my functionality · Issue #23179 · facebook/react
January 25, 2022 - import React, { useEffect, useState } from "react" export const useLocalStorage=<S extends { toString: () => string }>(key: string,initialState?: S | (() => S)):[S, React.Dispatch<React.SetStateAction<S>>] =>{ const [state, _setState] = useState<S>(initialState as S) useEffect(() => { const item = localStorage.getItem(key) if (item) _setState(typeof state === "string" ? item : JSON.parse(item)) }, []) useEffect(() => { localStorage.setItem(key, state.toString()) },[state]) const setState:React.Dispatch<React.SetStateAction<S>> = (value) => { _setState(value) } return [state,setState] } Link to code example: https://codesandbox.io/s/silly-browser-nws03?file=/src/useStorage.ts · All the useEffects have warnings from eslint-plugin-react-hooks. On the first useEffect: React Hook useEffect has missing dependencies: 'key' and 'state'. Either include them or remove the dependency array.
Author   Markos-Th09
🌐
DEV Community
dev.to › rangeoshun › optimize-useeffect-by-using-the-condition-itself-as-a-dependency-1c2j
Optimize useEffect by using a condition as a dependency - DEV Community
April 3, 2020 - const { loading } = useQuery(query, { /*... */ }) const [state, setState] = useState('initial'); useEffect(() => { if (loading && state !== 'loading') setState('loading') }) You cannot conditionally call useEffect or any other hook for that matter. In these cases, you add the condition in the function performing the side effect itself, while the variables checked in the condition go into the dependency array.