Reputation: 3753
Why do I need to wrap my setValue with a setTimeout in my React component?
This works
<Button onClick={() => acceptOne()}>
set value with setTimeout
</Button>
const acceptOne = () => {
setTimeout(() => {
setEditMode(false);
});
};
This does not...
<Button onClick={() => acceptTwo()}>
set value without setTimeout
</Button>
const acceptTwo = () => {
setEditMode(false);
};
Here is a CodeSandbox example for full code to demonstrate the issue.
I'm new to React and already had to use setTimout to get state to change like this. I feel this is most likely a beginner thing and there are some React specific things I don't yet understand. What is going on here, why doesn't setValue work when I don't use setTimeout?
Upvotes: 0
Views: 109
Reputation: 74738
It is happening because of the event propagation. As you can see you have bound an event to the parent div. So, whenever you click on button, parent div's event also executes.
Why it works with
setTimeout
?
Because it executes after div's event because it is been pushed to other async process and it takes time to execute.
You can add event.stopPropagation()
to stop the event to bubble up in the DOM:
const acceptOne = e => {
e.stopPropagation();
setEditMode(!editMode);
};
const acceptTwo = e => {
e.stopPropagation();
setEditMode(!editMode);
};
Now change the event either to:
onClick={acceptOne}
onClick={acceptTwo}
or:
onClick={e => acceptOne(e)}
onClick={e => acceptTwo(e)}
Upvotes: 2
Reputation: 621
https://codesandbox.io/s/charming-ganguly-mg4zx
I fixed it, there is the link.
So this is because of after the second click on the input it runners parent div click too because this input wrapped into a div element,
<div onClick={() => setEditMode(!editMode)}>
So when you put there setTimeout
the second input click runs before the parent div element click function, that's why it works. This is specifically connected with the javascript event loop, watch the video about event loop and you will understand whats happens there
https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=54s
Upvotes: 0
Reputation: 4474
<div onClick={() => setEditMode(true)}>
this is your problem. The parent DIV that wraps your buttons event is getting called as well as your button click. The delay that the setTimeout provides allows it to come in after the parent div, and therefore works. You can either restructure your HTML or do some event stopPropogation stuff to handle it.
Upvotes: 0
Reputation: 919
Issue was with the top line in your code <div onClick={() => setEditMode(true)}>
Review the updated snippet - https://codesandbox.io/s/charming-http-b637o
Logic is very well explained by Jai in his answer.
Upvotes: 0