Generally speaking, using setState inside useEffect will create an infinite loop that most likely you don't want to cause. There are a couple of exceptions to that rule which I will get into later.
useEffect is called after each render and when setState is used inside of it, it will cause the component to re-render which will call useEffect and so on and so on.
One of the popular cases that using useState inside of useEffect will not cause an infinite loop is when you pass an empty array as a second argument to useEffect like useEffect(() => {....}, []) which means that the effect function should be called once: after the first mount/render only. This is used widely when you're doing data fetching in a component and you want to save the request data in the component's state.
Generally speaking, using setState inside useEffect will create an infinite loop that most likely you don't want to cause. There are a couple of exceptions to that rule which I will get into later.
useEffect is called after each render and when setState is used inside of it, it will cause the component to re-render which will call useEffect and so on and so on.
One of the popular cases that using useState inside of useEffect will not cause an infinite loop is when you pass an empty array as a second argument to useEffect like useEffect(() => {....}, []) which means that the effect function should be called once: after the first mount/render only. This is used widely when you're doing data fetching in a component and you want to save the request data in the component's state.
For future purposes, this may help too:
It's ok to use setState in useEffect . To do so, however, you need to ensure you don't unintentionally create an infinite loop.
An infinite loop is not the only problem that may occur. See below:
Imagine that you have a component Comp that receives props from parent and according to a props change, you want to set Comp's state. For some reason, you need to change for each prop in a different useEffect:
DO NOT DO THIS
useEffect(() => {
setState({ ...state, a: props.a });
}, [props.a]);
useEffect(() => {
setState({ ...state, b: props.b });
}, [props.b]);
It may never change the state of a , as you can see in this example:
https://codesandbox.io/s/confident-lederberg-dtx7w
The reason this occurs is that both useEffect hooks run during the same react render cycle. When props.a and props.b change at the same time, each useEffect captures the same stale state value from before the update. As a result, when the first effect runs, it calls setState({ ...state, a: props.a }) . Then, the second effect runs immediately after and calls setState({ ...state, b: props.b}) with the same stale state value, thereby overwriting the first update. The result is that a never appears to update. The second setState replaces the first one rather than merging the two updates together.
DO THIS INSTEAD
The solution to this problem is to call setState like this:
useEffect(() => {
setState(previousState => ({ ...previousState, a: props.a }));
}, [props.a]);
useEffect(() => {
setState(previousState => ({ ...previousState, b: props.b }));
}, [props.b]);
For more information, check the solution here: https://codesandbox.io/s/mutable-surf-nynlx
With this approach, you will always receive the most updated and correct value of the state.
I saw a guy get reemed in some code he shared because he was using useState in a useEffect.
I have some areas of my code where I do this.
For example I will use tanstack to fetch data. I’ll tie a useEffect to that data and setState so that data can be edited in a form.
How else would you do this?
**** Edit. I meant setState in useEffect.
Working of `useState` function inside `useEffect` function
Bug: setState inside useEffect is unreliable in React 18
When you're using useState and useEffect at the same time, does useEffect run first before a hook variable is updated?
Current Value: {inputValue}
Previous Value: {previousInputValue.current}
); } More on reddit.comuseState in useEffect
Videos
setIsAuth doesn't cause the local variableisAuth to change its value. const data values can't be changed, and even if you defined it as let, that's not what setting state does. Instead, when you set state, the component rerenders. On that new render, the call to useState will return the new value, and you can use that new value for the new render.
The component renders for the first time. Then it runs the effect. The closure for the effect has the local variables from that first render, and your code uses those variables to log the false twice. Since you called set state, a new render will happen, and that new render will have different variables. When it's effect runs, it will log true twice, since that's the values in its closure.
Here are some comments in the code explaining how React setState will only update the local const once the component re-renders
import React, { useState, useEffect } from 'react';
const Authentication = () => {
// React will initialise `isAuth` as false
const [isAuth, setIsAuth] = useState(false);
useEffect(() => {
// Console log outputs the initial value, `false`
console.log(isAuth);
// React sets state to true, but the new state is not available until
// `useState` is called on the next render
setIsAuth(true);
// `isAuth` will remain false until the component re-renders
// So console.log will output `false` again the first time this is called
console.log(isAuth);
}, [isAuth]);
// The first time this is rendered it will output <p>False</p>
// There will be a re-render after the `setState` call and it will
// output <p>True</p>
return <div>{isAuth ? <p>True</p> : <p>False</p>}</div>;
};
export default Authentication;
Hello,So I am learning about useRef() and came across this example in w3schools.com
function App() {
const [inputValue, setInputValue] = useState("");
const previousInputValue = useRef("");
useEffect(() => {
previousInputValue.current = inputValue; }
, [inputValue]);
return ( <>
<input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
<h2>Current Value: {inputValue}</h2>
<h2>Previous Value: {previousInputValue.current}</h2>
</> );}Or https://www.w3schools.com/REACT/react_useref.asp (sorry; copy and paste is not working correctly and formatting is getting destroyed on reddit smh)
So, whenever someone changes the value in 'text' input tag (which is "synced" to inputValue hook), i can see useEffect() function is called.
now, in this following line, I am surprised that inputValue will have the old value and my understanding was useEffect (with inputValue as dependency) will run once that is updated.
useEffect(() => {
previousInputValue.current = inputValue;
}, [inputValue]);
Could someone please guide me on why inputValue won't have the latest/newest updated value inside useEffect()?