Scheduler uses `requestAnimationFrame` to post tasks to the browser.
If this happens at the beginning of a frame, the callback might not
fire until the subsequent frame, even if the main thread is idle.
Our theory was that this wouldn't be an issue in practice, because once
the first rAF fires, we schedule the next rAF as early as possible in
that frame. Combined with our heuristic for computing frame deadlines,
we shouldn't get any idle time in between frames — only before the
*first* frame.
This reasoning holds true when you have a small number of large tasks,
such as the ones posted by React. The idle time before the task starts
is negligible relative to the lifetime of the entire task.
However, it does not hold if you have many small tasks posted over a
span of time, perhaps spawned by a flurry of IO events. In this case,
instead of single, contiguous rAF loop preceded by an idle frame, you
get many rAF loops preceded by many idle frames. Our new theory is that
this is contributing to poor main thread utilization during page loads.
To try to reclaim as much idle time as possible, this PR adds two
experimental flags. The first one adds a `requestIdleCallback` call to
start the rAF loop, which will fire before rAF if there's idle time left
in the frame. (We still call rAF in case there isn't. We start working
in whichever event fires first.)
The second flag tries a similar strategy using `setTimeout(fn, 0)`. If
the timer fires before rAF, we'll assume that the main thread is idle.
If either `requestIdleCallback` or `setTimeout` fires before rAF, we'll
immediately peform some work. Since we don't have a real frame time that
we can use to compute the frame deadline, we'll do an entire frame
length of work. This will probably push us past the vsync, but this is
fine because we can catch up during the next frame, by which point a
real rAF will have fired and the loop can proceed the same way it
does today.
Test plan: Try this on Facebook to see if it improves load times
- redoes #15431 from scratch, taking on the feedback there
- unifies the messaging between "deprecated" and UNSAFE_ lifecycle messages. It reorganizes ReactStrictModeWarnings.js to capture and flush all the lifecycle warnings in one procedure each.
- matches the warning from ReactPartialRenderer to match the above change
- passes all the tests
- this also turns on `warnAboutDeprecatedLifecycles` for the test renderer. I think we missed doing so it previously. In a future PR, I'll remove the feature flag altogether.
- this DOES NOT do the same treatment for context warnings, I'll do that in another PR too
This returns the current value of ReactCurrentFiber and enables DevTools to append a custom (owner-only) component stack to warnings and errors in DEV mode.
Real Maps should now be used in RN JS engines. In theory this should
be faster (but might not actually be in practice), and it avoids hitting
upper bounds of property max counts.
We don't use these types of Maps in Fabric.
When executing a task, wraps the callback in an extra function whose
name includes the current priority level. Profiling tools with access
to function names can use this to determine the priority of the task.
1. Allow auxillary button clicks (i.e., middle mouse button) to trigger 'onPressStart' and 'onPressEnd', but never 'onPress'.
2. Report the button type – 'primary' or 'auxillary' – on the press event.
* [fail] reset IsThisRendererActing correctly
I missed this in https://github.com/facebook/react/pull/16039. I'd pointed at the wrong previous state, corrupting it in further use. This PR fixes that, and adds a test to make sure it doesn't happen again.
* warn for unacted effects only in strict mode
* only warn on unacted effects for strict / non sync modes
(basically, when `fiber.mode !== 0b0000`)
Warnings on unacted effects may be too noisy, especially for legacy apps. This PR fires the warning only when in a non sync mode (concurrent/batched), or when in strict mode. This should make updating easier.
I also added batched mode tests to the act() suite.
* explicitly check for modes before warning, explicit tests for all modes
* allow nested `act()`s from different renderers
There are usecases where multiple renderers need to oprate inside an act() scope
- ReactDOM.render being used inside another component tree. The parent component will be rendered using ReactTestRenderer.create for a snapshot test or something.
- a ReactDOM instance interacting with a ReactTestRenderer instance (like for the new devtools)
This PR changes the way the acting sigils operate to allow for this. It keeps 2 booleans, one attached to React, one attached to the renderer. act() changes these values, and the workloop reads them to decide what warning to trigger.
I also renamed shouldWarnUnactedUpdates to warnsIfNotActing
* s/ReactIsActing/IsSomeRendererActing and s/ReactRendererIsActing/IsThisRendererActing
* Add tail="collapsed" option
* Fix issue with tail exceeding the CPU time limit
We used to assume that this didn't suspend but this branch happens in
both cases. This fixes it so that we first check if we suspended.
Now we can fix the tail so that it always render an additional fallback
in this scenario.
* added flush sync test
* added code to run flushSync with ImmediatePriority
* added code to run flushSync with ImmediatePriority
* fixed flow error
* fixed flow error
* Add a bunch of optimizations to SuspenseList
We now are able to bail out of reconciliation and splitting out the tail
during deep updates that hasn't changed the child props. This only
works while the list wasn't suspended before.
I also moved the second render of the "head" to the complete phase. This
cleans it up a bit for the tail collapsing PR.
For this second pass I also use a new technique of resetting the child
Fibers for the second pass. This is effectively a fast path to avoid
reconciling the children against props again.
* Move to didSuspend from SuspenseListState to the effectTag
The effectTag now tracks whether the previous commit was suspended.
This frees up SuspenseListState to be render-phase only state.
We use null to mean the default "independent" mode.
* Rename to SuspenseListState to SuspenseListRenderState
* Reuse SuspenseListRenderState across render passes
* Add optimization to bail out of scanning children if they can't be suspended
This optimized the deep update case or initial render without anything
suspending.
We have some information available to us that tell us if nothing has
suspended in the past and nothing has suspended this render pass.
This also fixes a bug where we didn't tag the previous render as having
suspended boundaries if we didn't need to force a rerender.
* rm printChildren
oops
* Slightly improve performance of hydration.
Avoid loading nodeType and data couple times from the same node in a row,
but instead load them only once, which will help engines to run this code
faster, especially during startup of the application. The general approach
is still not ideal, since hydrating this way forces the browser engine
to materialize JavaScript wrapper objects for all DOM nodes, even if they
are not interesting to hydration itself.
* Fix condition for COMMENT_NODEs.
* Improve general code readability