Commit Graph

10927 Commits

Author SHA1 Message Date
Andrew Clark
cc24d0ea56 Invariant that throws when committing wrong tree (#15517)
If React finishes rendering a tree, delays committing it (e.g.
Suspense), then subsequently starts over or renders a new tree, the
pending tree is no longer valid. That's because rendering a new work-in
progress mutates the old one in place.

The current structure of the work loop makes this hard to reason about
because, although `renderRoot` and `commitRoot` are separate functions,
they can't be interleaved. If they are interleaved by accident, it
either results in inconsistent render output or invariant violations
that are hard to debug.

This commit adds an invariant that throws if the new tree is the same as
the old one. This won't prevent all bugs of this class, but it should
catch the most common kind.

To implement the invariant, I store the finished tree on a field on the
root. We already had a field for this, but it was only being used for
the unstable `createBatch` feature.

A more rigorous way to address this type of problem could be to unify
`renderRoot` and `commitRoot` into a single function, so that it's
harder to accidentally interleave the two phases. I plan to do something
like this in a follow-up.
2019-05-13 16:15:50 -07:00
Andrew Clark
83fc258f29 Remove <ConcurrentMode /> (#15532)
Use createSyncRoot instead.
2019-05-13 16:10:00 -07:00
Andrew Clark
283ce53204 Add ReactDOM.unstable_createSyncRoot (#15504)
* Add ReactDOM.unstable_createSyncRoot

- `ReactDOM.unstable_createRoot` creates a Concurrent Mode root.
- `ReactDOM.unstable_createSyncRoot` creates a Batched Mode root. It
does not support `createBatch`.
- `ReactDOM.render` creates a Legacy Mode root. It will eventually be
deprecated and possibly moved to a separate entry point, like
`react-dom/legacy`.

* Rename internal ReactRoot types
2019-05-13 15:30:03 -07:00
Andrew Clark
862f499fac Add Batched Mode (#15502)
* Add Batched Mode

React has an unfortunate quirk where updates are sometimes synchronous
-- where React starts rendering immediately within the call stack of
`setState` — and sometimes batched, where updates are flushed at the
end of the current event. Any update that originates within the call
stack of the React event system is batched. This encompasses most
updates, since most updates originate from an event handler like
`onClick` or `onChange`. It also includes updates triggered by lifecycle
methods or effects. But there are also updates that originate outside
React's event system, like timer events, network events, and microtasks
(promise resolution handlers). These are not batched, which results in
both worse performance (multiple render passes instead of single one)
and confusing semantics.

Ideally all updates would be batched by default. Unfortunately, it's
easy for components to accidentally rely on this behavior, so changing
it could break existing apps in subtle ways.

One way to move to a batched-by-default model is to opt into Concurrent
Mode (still experimental). But Concurrent Mode introduces additional
semantic changes that apps may not be ready to adopt.

This commit introduces an additional mode called Batched Mode. Batched
Mode enables a batched-by-default model that defers all updates to the
next React event. Once it begins rendering, React will not yield to
the browser until the entire render is finished.

Batched Mode is superset of Strict Mode. It fires all the same warnings.
It also drops the forked Suspense behavior used by Legacy Mode, in favor
of the proper semantics used by Concurrent Mode.

I have not added any public APIs that expose the new mode yet. I'll do
that in subsequent commits.

* Suspense in Batched Mode

Should have same semantics as Concurrent Mode.

* Use RootTag field to configure type of root

There are three types of roots: Legacy, Batched, and Concurrent.

* flushSync should not flush batched work

Treat Sync and Batched expiration times separately. Only Sync updates
are pushed to our internal queue of synchronous callbacks.

Renamed `flushImmediateQueue` to `flushSyncCallbackQueue` for clarity.
2019-05-13 14:30:39 -07:00
Dominic Gannaway
fec74f99da Event API: ensure preventDefault works for nested targets (#15633) 2019-05-13 13:45:48 +01:00
Andrew Clark
edfedf3ae9 Fork ReactSharedInternals for UMD builds (#15617) 2019-05-10 13:51:39 -07:00
Andrew Clark
39ef609e7c Update test to fix CI 2019-05-10 11:12:24 -07:00
Andrew Clark
5b6eb55e1c Remove scheduler from React package dependencies (#15616)
Scheduler is used by the renderers, but not the isomorphic package.
2019-05-10 11:01:04 -07:00
Sebastian Markbåge
0803d22479 Don't consider "Never" expiration as part of most recent event time (#15606)
* Don't consider "Never" expiration as part of most recent event time

This doesn't happen with deprioritization since those are not "updates"
by themselves so they don't go into this accounting.

However, they are real updates if they were scheduled as Idle pri using
the scheduler explicitly. It's unclear what suspense should do for these
updates. For offscreen work, we probably want them to commit immediately.
No point in delay them since they're offscreen anyway. However if this is
an explicit but very low priority update that might not make sense.
So maybe this means that these should have different expiration times?

In this PR I just set the suspense to the lowest JND.

However, we don't want is for these things to commit earlier in case
they got batched in with other work so I also ensured that they're not
accounted for in in the workInProgressRootMostRecentEventTime calculation
at all. This makes them commit immediately if they're by themselves, or
after the JND of whatever they were batched in with.

Ultimately, I think that we should probably never schedule anything at
Never that isn't truly offscreen so this should never happen.

However, that begs the question what happens with very low pri work that
suspends. Do we always work at that level first?

* Adjust test to account for the new shorter suspense time
2019-05-10 10:53:20 -07:00
Dominic Gannaway
90f54d77f3 Event API: add follow up event unwind test (#15612) 2019-05-10 13:36:54 +01:00
Dominic Gannaway
91a044e31f Event API: add key modifiers to Press events (#15611) 2019-05-10 13:32:11 +01:00
Dominic Gannaway
3d8b836e22 Event API: ensure we pop context for event system fibers (#15599) 2019-05-09 17:01:18 +01:00
Dominic Gannaway
e33e32db04 Event API: normalize event timeStamp property to be in event system (#15598) 2019-05-09 16:05:25 +01:00
Dominic Gannaway
3669b90101 Event API: add more warnings for responder based events (#15597) 2019-05-09 15:31:18 +01:00
Dominic Gannaway
05d08500b2 Experimental Event API: Press event properties (#15586) 2019-05-08 20:29:03 +01:00
Dominic Gannaway
51e66cf9fa Experimental Event API: reduce code size of event modules (#15590) 2019-05-08 19:09:32 +01:00
Dominic Gannaway
8abf243b86 Ensure touch events are properly handled for pageX and pageY (#15587) 2019-05-08 19:08:15 +01:00
Sebastian Markbåge
c7398f3396 Add Suspense Boundary Context (and unstable_avoidThisFallback) (#15578)
* Avoidable suspense boundaries

* Move the context out of SuspenseComponent

* Use setDefaultShallowSuspenseContext instead of passing 0
2019-05-07 18:08:05 -07:00
Andrew Clark
f9e60c8a19 Warn when suspending at wrong priority (#15492)
* Warn when suspending at wrong priority

Adds a warning when a user-blocking update is suspended.

Ideally, all we would need to do is check the current priority level.
But we currently have no rigorous way to distinguish work that was
scheduled at user- blocking priority from work that expired a bit and
was "upgraded" to a higher priority. That's because we don't schedule
separate callbacks for every level, only the highest priority level per
root. The priority of subsequent levels is inferred from the expiration
time, but this is an imprecise heuristic.

However, we do store the last discrete pending update per root. So we
can reliably compare to that one. (If we broaden this warning to include
high pri updates that aren't discrete, then this won't be sufficient.)

My rationale is that it's better for this warning to have false
negatives than false positives.

Potential follow-ups:
- Bikeshed more on the message. I don't like what I landed on that much
but I think it's good enough to start.
- Include the names of the components that updated. (The ideal place to
fire the warning is during the setState call but we don't know if
something will suspend until the next update. Maybe we could be clever
and warn during a subsequent update to the same component?)

* Move Suspense priority check to throwException
2019-05-07 16:50:04 -07:00
Nicolas Gallagher
89d8d1435f Add React.unstable_createEventComponent (#15580)
API for creating event components from event responders.
2019-05-07 12:36:42 -07:00
Brian Vaughn
6da04b5d88 Fix interaction tracing for batched update mounts (#15567)
* Added failing test for act+interaction tracing
* Mark pending interactions on root for legacy unbatched phase
2019-05-06 12:59:48 -07:00
Dominic Gannaway
d38cfd452f Ensure TouchHitTarget element is server side rendered with hit slop (#15385)
* Follow up to 15381

* Add back in hit slop properties

* Prettier

* Fix lint

* move hydration update out of DEV block

* Remove pointer-events:auto
2019-05-06 20:13:23 +01:00
Nicolas Gallagher
2e5d1a8b9e React Events: fix cancel events for Press (#15563)
* Fixes a bug in the cancellation logic. The cancel events are now correctly listened to on the root.
* Fixes cancellation in Safari by using the dragstart event as a proxy for cancellation (i.e., the event dispatched when move-during-press occurs on an anchor tag)
2019-05-03 15:33:21 -07:00
Nicolas Gallagher
307e0a7d7d React Events: cancel onLongPress for large enough moves (#15562)
Implements the behaviour from React Native's Pressability.
2019-05-03 12:59:55 -07:00
Dominic Gannaway
339366c461 Event API: Support press reentry for pointer events (#15560) 2019-05-03 18:32:50 +01:00
Dominic Gannaway
ec6691a687 Event API: remove isTargetDirectlyWithinEventComponent (#15546) 2019-04-30 17:38:48 +01:00
Dominic Gannaway
a6e30001fb Delete duplicate Focus.js (#15540)
This file was renamed to the lower case version, but as Mac filesystems are typically case insensitive, it was never removed.
2019-04-30 12:20:44 +01:00
Dominic Gannaway
f7993d5477 Delete duplicate Hover.js (#15539)
This file was renamed to the lower case version, but as Mac filesystems are typically case insensitive, it was never removed.
2019-04-30 12:13:07 +01:00
Dominic Gannaway
c8ee10037a Delete duplicate Swipe.js (#15541)
This file was renamed to the lower case version, but as Mac filesystems are typically case insensitive, it was never removed.
2019-04-30 12:11:26 +01:00
Dominic Gannaway
494716c9b4 Delete duplicate Drag.js (#15537)
This file was renamed to the lower case version, but as Mac filesystems are typically case insensitive, it was never removed.
2019-04-30 12:07:24 +01:00
Dominic Gannaway
377846fef8 Delete duplicate Press.js (#15538)
This file was renamed to the lower case version, but as Mac filesystems are typically case insensitive, it was never removed.
2019-04-30 12:06:44 +01:00
Dominic Gannaway
379515e83e Follow up to 15535 (#15536) 2019-04-30 12:04:19 +01:00
Dominic Gannaway
bd88982fbf Event API: use capture for all event listeners using experimental responder system (#15526) 2019-04-30 11:40:45 +01:00
Andrew Clark
72ca3c60e7 Bump scheduler version to 0.14.0 (#15395) 2019-04-29 18:10:11 -07:00
Andrew Clark
7882c41f60 Use lowercase entry points for event modules (#15535)
Matches npm convention
2019-04-29 16:25:56 -07:00
Nathan Schloss
43c4e5f348 Add method for forcing a lower framerate 2019-04-29 15:51:58 -07:00
Brian Vaughn
1b752f1914 Fixed potential interaction tracing leak in Suspense thennable memoization (#15531)
Audited the other places we call unstable_wrap() in React DOM and verified that they didn't have this similar problem.
2019-04-29 15:04:52 -07:00
Eli White
12e5a13cf2 [React Native] Inline calls to FabricUIManager in shared code (#15490)
* [React Native] Inline calls to FabricUIManager in shared code

* Call global.nativeFabricUIManager directly as short term fix

* Add flow types

* Add nativeFabricUIManager global to eslint config

* Adding eslint global to bundle validation script
2019-04-29 14:31:16 -07:00
Nicolas Gallagher
2cca18728e React Events: add onFocusVisibleChange to Focus (#15516)
Called when focus visibility changes. Focus is only considered visible if a
focus event occurs after keyboard navigation. This provides a way for people to
provide visual focus styles for keyboard accessible UIs without those styles
appearing if focus is triggered by mouse, touch, pen.
2019-04-29 13:52:15 -07:00
Nicolas Gallagher
cc5a49379b React Events: FocusScope tweaks and docs (#15515)
* FocusScope: rename trap to contain.
* FocusScope: avoid potential for el.focus() errors.
* FocusScope: add docs.
* Update docs formatting.
2019-04-26 13:38:01 -07:00
Dominic Gannaway
796c67a25f Event API: responder event types should not re-register on EventComponent update (#15514) 2019-04-26 21:33:54 +01:00
Dominic Gannaway
c4d1dcb533 React Events: core API documentation followup (#15506) 2019-04-26 15:47:28 +01:00
Dan Nate
41ef1961c1 Update TopLevelEventTypes.js (#15511)
Fix grammar of code comment.
2019-04-26 14:58:32 +02:00
Dominic Gannaway
7a482af5d8 Event API: Fix bug where Press root events were not being cleared (#15507) 2019-04-26 10:30:38 +01:00
Nicolas Gallagher
a14e24efab React Events: core API documentation (#15505) 2019-04-26 08:11:40 +01:00
Dominic Gannaway
8658611b6c Event API: ensure event keys are unique + add validation (#15501) 2019-04-26 08:00:57 +01:00
Nicolas Gallagher
d9839740ef React events: remove unused types (#15503) 2019-04-25 15:11:53 -07:00
Nicolas Gallagher
0b34311705 React events: fix press end event dispatching (#15500)
This patch fixes an issue related to determining whether the end event occurs
within the responder region. Previously we only checked if the event target was
within the responder region for moves, otherwise we checked if the target was
within the event component. Since the dimensions of the child element can
change after activation, we need to recalculate the responder region before
deactivation as well if the target is not within the event component.
2019-04-25 13:00:22 -07:00
Dominic Gannaway
d1f667acc0 Event API: follow up fixes for FocusScope + context changes (#15496) 2019-04-25 20:10:33 +01:00
Kunuk Nykjær
c530639dd2 Minor code structure adjustments to the bundles.js file (#15079)
* simplify

* fix error

* use deepFreeze

* move comments
2019-04-25 16:24:01 +01:00