Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: event.preventDefault is wrecking havoc with startTransition #18020

Closed
arackaf opened this issue Feb 11, 2020 · 7 comments · Fixed by #18515
Closed

Bug: event.preventDefault is wrecking havoc with startTransition #18020

arackaf opened this issue Feb 11, 2020 · 7 comments · Fixed by #18515

Comments

@arackaf
Copy link

arackaf commented Feb 11, 2020

React version: 241c446

Steps To Reproduce

https://codesandbox.io/s/romantic-gates-2hrjp

  1. Click "Show A" to render the lazy component.
  2. Type into the input whose placeholder says it works. startTransition will call, inline loading will show for 2 seconds, then the Suspense boundary will trigger.
  3. Click the "update" button - same as above - everything works
  4. Now type into the input whose placeholder says it doesn't work. Note that the inline placeholder stays up for the entire time; the Suspense boundary never shows.
  5. Now note that steps 2 or 3 will likely immediately show the suspense boundary. The bypassed rendering of the Suspense boundary from step 4 seems to be backed up, stuck somewhere, and is now unleashed.

Note that steps 2 and 3 are optional. No matter what, the preventDefault that's called in step 4 causes this incorrect behavior no matter whether steps 2 or 3 have been exercised.

Link to code example: see above

The current behavior

startTransition should suspend after the timeout even if event.preventDefault is called.

The expected behavior

it does not

@arackaf arackaf added the Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug label Feb 11, 2020
@gaearon gaearon added Component: Concurrent Features Type: Bug and removed Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug labels Feb 12, 2020
@gaearon
Copy link
Collaborator

gaearon commented Feb 12, 2020

I don't understand what is happening here. This is odd.

@arackaf
Copy link
Author

arackaf commented Feb 12, 2020

@gaearon - you don't understand what incorrect behavior my repro is showing, or are you saying you can't tell why / how React is broken? You added the "Bug" label and removed "Unconfirmed" so I assume the latter but let me know if you need me to clarify

@jddxf
Copy link
Contributor

jddxf commented Feb 15, 2020

Here's what is going on:

The call of preventDefault keeps input values unchanged, so the pending discrete updates are not flushed at the end of the keydown event.

if (controlledComponentsHavePendingUpdates) {
// If a controlled event was fired, we may need to restore the state of
// the DOM node back to the controlled value. This is necessary when React
// bails out of the update without touching the DOM.
flushDiscreteUpdatesImpl();

Instead, they are flushed at the beginning of the keyup event. At that time, a timeout to commit the suspended root has already been scheduled. But it is cancelled since the flush needs to prepare a fresh stack to perform work.

if (timeoutHandle !== noTimeout) {
// The root previous suspended and scheduled a timeout to commit a fallback
// state. Now that we have additional work, cancel the timeout.
root.timeoutHandle = noTimeout;
// $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
cancelTimeout(timeoutHandle);
}

And no timeout would be scheduled again for some reason. Thus the placeholder is never showed.

@gaearon
Copy link
Collaborator

gaearon commented Mar 30, 2020

@jddxf Would you be interested in writing a failing test for this? Recent bugfixes like #18411 and #18412 might provide you with some inspiration.

@jddxf
Copy link
Contributor

jddxf commented Mar 31, 2020

@gaearon I'd love to if it's not too late to do it this weekend.

@gaearon
Copy link
Collaborator

gaearon commented Mar 31, 2020

Anytime! In general, all issues tagged with Concurrent Mode would benefit from failing tests. Even if we don't get to fixes soon.

@arackaf
Copy link
Author

arackaf commented Apr 8, 2020

Woo hoo - thanks everyone!!! 👊👌💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants