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.
Do useEffects run if the component state doesn't change regardless of the dependencies they have been provided with?
react.js - React setState function in useEffect - Code Review Stack Exchange
React useState hook with dependency - javascript
Can someone explain useEffect dependency arrays like im 5?
Videos
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
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.
The context of an application does not persist across multiple pageloads or refreshes except through the few ways that allow for persistent data - such as local storage, cookies, and an API with a server somewhere. For the same reason, doing
let num = 5;
button.onclick = () => { num = 10; }
results in num still being 5 after you click and reload the page - because reloading the page starts the script from the very beginning again, on the new page.
If you want to keep track of whether that particular section of code has ever run before, use a flag in storage, eg:
useEffect(() => {
if (localStorage.hasVisitedBefore) return;
localStorage.hasVisitedBefore = 'yes';
// rest of effect hook
, []);
I need some helping understand why the code below runs every time I refresh the page even though I provided an empty dependency array?
Every time you refresh the page, the React component mounts for the first time.
One of the rules of React hooks is that useEffect must include all variables that it references in its dependency array. That's why you're getting the error. You can have additional variables, like varB, but you cannot exclude one, otherwise you could run into some wonky behavior.
A way around it is to use a ref, which allows you to store the value in a way that never triggers a render. The ref will need to be included in the dependency array, but since it never changes it won't trigger the useEffect again.
const varARef = useRef(varA)
useEffect(()=> {
DO SOMETHING TO varARef.current;
}, [varARef, varB])
Note that if you do want varARef.current to stay in sync with varA, you'll want to add a line for that:
const varARef = useRef(varA)
varARef.current = varA
useEffect(()=> {
DO SOMETHING TO varARef.current;
}, [varARef, varB])
If you have to update the state of a variable using its current state the best way to do it is using a callback inside setState.
If you change your code like this no issue will be triggered.
[varB, setVarB] = useState("");
[counter, setCounter] = useState(0);
useEffect(()=>{
setCounter(currentCounter => currentCounter+1);
},[varB]) // No warning here
Full answer: useEffect has a missing dependency when updating state based on current value