This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
How does JavaScript mechanism behind react hooks work?
(2 answers)
Closed 3 years ago.
I am using useState hook inside onClick handler to change and track the focus state. I set it to false initially and then change it to true and false several times in the handler. After each change, I do console.log(focus) and I expect it to be respective to the changes made.
function App() {
const [focus, setFocus] = useState(false);
return (
<div
className="App"
onClick={() => {
console.log(focus);
setFocus(true);
console.log(focus);
setFocus(false);
console.log(focus);
}}
>
<h1>App</h1>
</div>
);
}
In my case, in this code snippet, I expect to see in console false, true and then false again, but I see all of them false.
Why does it happen? I feel I am missing something quite fundamental here.
When you set the state, the component will be re-rendered. State changes are not synchronous in nature. Try adding a console.log below your useState line and you'll see that it gets called every time you set the focus because the entire component is re-rendered.
Related
This question already has answers here:
Function inside functional component in React hooks - Performance
(8 answers)
Closed 6 months ago.
I'm currently learning react.js and I just want to ask a question on how to properly create an event handler function inside a function component.
Pardon me since most examples in the official documentation are using class for this types of components.
I have an example code below that seems to work fine, but I'm not sure if this is the correct way/best practice when creating an event handler inside a function component, since every time the state changes I assume that the handleClick function is also recreated isn't it? This affects the performance every time we re-render right?
Say for example when I add more elements inside the return statement that can also trigger an event, and each event has a corresponding event handler that is also declared in that same function component, that might be an overhead for those extreme cases 'isn't that correct?
As far as I know this is not a problem on class components because they have a separate render() method so the event handler functions are not recreated, how do we do this in function components?
function Toggle (props) {
const [isToggleOn, setToggle] = React.useState(false)
function handleClick (e) {
setToggle(() => !isToggleOn)
}
return (
<button onClick={handleClick}>
{isToggleOn ? 'ON' : 'OFF'}
</button>
)
}
If you don't want the handleClick function to be recreated on each render, you should use useCallback hook.
const handleClick = useCallback(() => {
setToggle((previousState) => !previousState)
}, [])
This way, handleClick is created only at the initial render because the useCallback's dependency array is empty.
You might also notice that I removed the usage of isToggleOn and instead use the previous state in the setToggle so your function don't need to depend on isToggleOn.
This question already has answers here:
Updating state to the same state directly in the component body
(2 answers)
Closed 4 months ago.
The code below should not trigger a re-render because it's passing the same initial value right? But it instead causes 'Too many re-renders' error.
function Test() {
const [counter, setCounter] = useState(0)
setCounter(0)
return <></>
}
Edit: If you setCounter(0) in a function and attach it to a button click, it won't trigger a re-render since it has the same value so why does it trigger re-render when placed in the body of the component? I am aware of the useEffect with empty dependency array to avoid the infinite loop.
If you do this, you'll see that it doesn't re-render:
function Test() {
const [counter, setCounter] = useState(0)
console.log('render');
const set = () => {
setCounter(0)
};
return <button onClick={set}>Set</button>
}
In React, It does not Matter You are Updating Same Value or Not. If you Update the State It Will rerender the Component..
In your case , You Have SetState in the body of the Component.. So it will rerender and Cause an Infinite Loop..
If you Just want to Update Once, use useEffect instead.
useEffect(() => {
setCounter(0)
},[])
I hope it's not too late, but I asked the same question too and got a really good and logical explanation for this.
And as some people might think that the setState function triggers re-rendering anyway even if the state is the same - that's not true at all.
See this link to my question: Updating state to the same state directly in the component body
This question already has answers here:
useState not updating for some reason?
(2 answers)
Closed 1 year ago.
function LoginComponent(){
const [clicked, setClicked] = useState(false)
function handleClick(){
console.log('before', clicked)
setClicked(true)
console.log('after', clicked)
}
return(
<a onClick={handleClick}>
random text
</a>
)
}
When I run this, the console outputs before false after false. Why is this? I have no clue why this behavior is like this.
Because setting state is an asynchronous action.
It takes some time to update.
Check react documentation link to know more
You can check the updated value by
useEffect(()=> {
console.log("clicked", clicked);
},[clicked]);
There are couple of reasons for this behavior:
State is updated asynchronously
In any particular render, state and props don't change, changes are only reflected when component re-renders
If you want to log the updated value of clicked, put the log statement in the useEffect hook.
You can't update and log the updated value of any state variable in the same render. Component will have to re-render to reflect changes due to state update.
Similarly, if you want to call a function with the updated value of clicked, call the function from inside the useEffect hook.
setClicked is asynchronous. You must check the state updated in useEffect
function LoginComponent(){
const [clicked, setClicked] = useState(false)
function handleClick(){
setClicked(true)
}
useEffect(() => {
console.log(clicked);
},[clicked])
return(
<a onClick={handleClick}>
random text
</a>
)
}
This question already has an answer here:
Why does useState cause the component to render twice on each update?
(1 answer)
Closed 2 years ago.
const App = () => {
const [ counter, setCounter ] = useState(0)
console.log(counter)
return (
<>
<div>You clicked {counter} times.</div>
<button onClick={ () => setCounter(counter+1) }>Click me!</button>
</>
)
}
Here's my react component. My question is when I run this, I see 0 two times in the console. Then when I click on the button, I see 1 two times in the console. Can anyone explain why does that happen? I was expecting 0, 1, 2 to be printed only once in the console whenever I click on the button.
Please forgive if this question has already been answered or my title of the question is not related with what I'm asking as this is my first question here.
It is because of React.StrictMode
If you go to your index.js , you will find that your App component is wrapped with <React.StrictMode>. If you strip off the StrictMode you will notice that your App component will render only once.
Refer the below doc to understand StrictMode
Strict mode can’t automatically detect side effects for you, but it
can help you spot them by making them a little more deterministic.
This is done by intentionally double-invoking the following functions:
Class component constructor, render, and shouldComponentUpdate methods
Class component static getDerivedStateFromProps method Function
component bodies State updater functions (the first argument to
setState) Functions passed to useState, useMemo, or useReducer
Please refer: https://reactjs.org/docs/strict-mode.html
return (<React.StrictMode><App /><React.StrictMode>)
This would solve your problem.
This question already has answers here:
Why does calling react setState method not mutate the state immediately?
(9 answers)
Closed 5 years ago.
onSelectedRow(user, clickEvent){
const state = this.state;
this.state['userId'] = clickEvent.target.getAttribute(user['mta:UserId']);
this.setState(state);
console.log(user['mta:UserId']);
console.log(this.state);
}
Okay, so when I click a table-cell in my app this function gets called.
The point of it is to take the users UserId and set the state. This UserId is later on passed down to a child component and used to get specific information. The problem is that I get the correct data in the first console.log but when I then log this.
state the userId is still null for some reason. Anyone had similiar problems?
It's most probably because you're not updating the const state, but instead trying to mutate the state itself.
Also, you don't have to make a copy of a state. You can update just the field you want to update like this:
onSelectedRow(user, clickEvent) {
this.setState({
userId: clickEvent.target.getAttribute(user['mta:UserId'])
}, () => { console.log(this.state.userId) });
console.log(user['mta:UserId']);
}
Also, your console.log won't read immediate change in the state as setState is an async action.
If you really want to read it you can pass the callback to the setState which fill fire right after the state is updated, or use React's lifecycle method componentDidUpdate().