set the state value in Useeffect function and want to use that value after 5 lines in filter function but the state show the empty value means it update the state late how to solve this error
setState is an asynchronous function. Let's take this example
const [testState, setTestState] = useState()
and in a useEffect, if you call lets say setTestState('1234') and the very next line you try to log it console.log(testState) - this wont log '123' as the setTestState is asynchronous, which is happening in your case.
Solution -
Put the filter function in a different useEffect and pass the state in the dependency array
Related
const [liveRows, setLiveRows] = useState([]);
function addRow(arr){
setLiveRows([...liveRows, arr]);
console.log(liveRows)
}
When I run the addRow function with an array, the map used in the page re-renders fine, but the array in the log shows empty.
Running the function again shows the previous state of the array before the update, but the re-render shows correctly.
I am assuming this is due to the spread but am lost how to correct it?
This is expected behavior. setState is not an asynchronous! setState always work after the next render.
The set function only updates the state variable for the next render. If you read the state variable after calling the set function, you will still get the old value that was on the screen before your call.
For details : https://beta.reactjs.org/reference/react/useState
const [val,setVal] = React.useState(0);
Sometimes I see this in other peoples code
setVal(()=>val);
Does that have any difference from this.
setVal(val);
As the comments point out, half the time this syntax makes no difference. Where it does comes into play is asynchronisity. For example, say you have a setTimeout call in a useEffect and it waits a few seconds and then performs a state update, but while awaiting, the state is updated from somewhere else in the component. If you were to reference the state value in the setTimeout callback it would be a stale value and so if you called setMyState(prevState + 1) you would be off by 1. However if you use setMyState(prevState => prevState + 1) you have accessed the most up-to-date state value.
Also, it is very useful when you don't want to reference the state value in a hook like useEffect. Anything included in a dependency array will cause the hook to update and that can produce chain reactions or fire off a useEffect. when using setMyState(prev => prev + 1) inside the hook, you can avoid referencing the state value itself.
I am facing a strange issue when trying to call a cleanup function on component unmount with useEffect.
In my useEffect return I call a useCallback function where the dependencies are added correctly. In there a check the state variable called status but this variable never get updated from the initial state. I cannot pass the variable to the useEffect as I want to trigger it only when the component unmounts for specific reasons.
I recreated a simplified version in the codepen here and I can't get my head around this. Maybe someone knows why this is happening?
Thank you!
(this just started happening recently and it was working previously so I'm even more confused!)
Thank you for your answers.
So, I finally found out what happens.
useEffect creates a closure and the function is in that closure, which means that the status, being a string, remains as for the first render (when the closure gets created) and it never gets updated.
A way of giving this is using useRef, as mentioned by #ilkerkaran, but that's because it creates an object, which means that the ref.current property has a link to the original one and it's always in sync.
Another way would be to do useMemo and return an object with the status property, which is practically useRef under the hood.
So practically, if the state were an object and we passed state as a dependency, the stayus property would work as expected for the same reason. I hope this helps also someone else and saves some time
Actually that's not what happens on your code. The callback function is updated according to dependency array. You can see that by calling remove() just above useEffect. That way, the func will be executed on every render.
What happens in your example;
it renders, (by pressing the toggle button for the first time)
then you trigger second render by calling setStatus("mounted") in useEffect (by pressing the toggle button for the second time)
then it renders for te last time for unmount with the default state values
Last part also bugs me actually. You can observe this behaviour by putting a simple console.log just above your useEffect definition.
You also can work around this by using useRef instead of useState
The reason for this is your useEffect .
React.useEffect(() => {
setStatus("mounted")
return () => remove()
}, [])
You have an useEffect with the dependency set to []. This means that your useEffect will run only once . So this is how the flow goes your component is executed from the top to bottom so you create a remove function which at this point of time has your initial state as not mounted . Now your dom get painted. You useEffect gets called you set the state now you get a brand new remove function . Now you unmount your component the clean up will use the remove function from the first render.
In order for your state to reflect in the remove you need to add status as the dependency in the useEffect .
React.useEffect(() => {
setStatus("mounted")
return () => remove()
}, [status])
const [count,setCount]=useState(5)
useEffect(()=>{
setCount(10)},[count])
In above code if i am updating state without async operation useEffect doesn't goes to infite loop.While in below code if i update sate through asysnc operation it goes to infite loop can some one tell me the behavior of useEffect in the case of async oeration?
const [count,setCount]=useState(5)
useEffect(()=>{
//some async operation
.then(response)=>{
setCount(response.data)}},[count])
This is because numbers are compared to values and objects by references. Each time async operation result in new object reference, hence useEffect triggers.
In case of number like setCount(5) will not trigger again as second time 5 is the same variable as previous.
Thats a good question!
In the first snippet you were setting the count to 10, that value is not changing dynamically and hence it will change once and wait for the count to change again which will not happen over there, whereas in the second snippet once the async operation is completed it will update the count and because of this count update useEffect will be triggered again along with the async operation in it. So it goes into a recursive updation.
If you want, you can change the first snippet like this to see the recursive updation
setCount(count + 1);
This is the catch of hooks and how they update state, if your previous state value and current state value is same then react functional component won't re-renders, so it is advisable if you are working with object type of state then always create new object or use spread operator for updating any property inside object while updating your state. In your case setCount(10) will always return a constant value of 10 so useEffect won't trigger infinite times as count is theoretically changed once from 5 to 10, but for an API request it will always returns an object with new reference so it'll create an infinite loop. You can also do setCount(10) inside your API result and it also won't trigger useEffect as count is basically never changed from 10 except from a change 5 to 10.
I have a very simple react application. I am trying to set a state variable and then immediately after console.log that variable but am getting a blank value.
var [techFilterTerm, setTechFilterTerm] = useState('');
setTechFilterTerm('Test');
console.log(techFilterTerm);
I expect on the first render this would show "Test" in the console - it however shows the empty string. What is going on here?
If I understand your problem correctly you want to know the updated value and for that you can use useEffect api which will get called whenever there is change in one of the value you want to observe. The values you want to observe you need to pass as second parameter as array in useEffect. In your case you want to know the updated value for techFilterTerm so you can pass techFilterTerm as second argument to useEffect as below.
useEffect(() => {
//here you will get the updated value whenever there is change in value
},[techFilterTerm]);
here is the link for more info on useEffect.
https://reactjs.org/docs/hooks-effect.html