* Don't call onCommit et al if there are no effects
Checks `subtreeFlags` before scheduling an effect on the Profiler.
* Fix failing Profiler tests
The change to conditionally call Profiler commit hooks only if updates were scheduled broke a few of the Profiler tests. I've fixed the tests by either:
* Adding a no-op passive effect into the subtree or
* Converting onPostCommit to onCommit
When possible, I opted to add the no-op passive effect to the tests since that that hook is called later (during passive phase) so the test is a little broader. In a few cases, this required adding awkward act() wrappers so I opted to go with onCommit instead.
Co-authored-by: Brian Vaughn <bvaughn@fb.com>
There were a few pairs of commit phase functions that were almost
identical except for one detail. I've refactored them a bit to
consolidate their implementations:
- Lifted error handling logic when mounting a fiber's passive hook
effects to surround the entire list, instead of surrounding each effect.
- Lifted profiler duration tracking to surround the entire list.
In both cases, this matches the corresponding code for the layout phase.
The naming is still a bit of a mess but I'm not too concerned because
my next step is to refactor each commit sub-phase (layout, mutation)
so that we can store values on the JS stack. So the existing function
boundaries are about to change, anyway.
DevTools shared Babel config previously supported IE 11 to target Hermes (for the standalone backend that gets embedded within React Native apps). This targeting resulted in less optimal code for other DevTools targets though which did not need to support IE 11. This PR updates the shared config to remove IE 11 support by default, and only enables it for the standalone backend target.
Instead of calling `onPostCommit` in a separate phase, we can fire
them during the same traversal as the rest of the passive effects.
This works because effects are executed depth-first. So by the time we
reach a Profiler node, we'll have already executed all the effects in
its subtree.
* Improve DevTools editing interface
This commit adds the ability to rename or delete keys in the props/state/hooks/context editor and adds tests to cover this functionality. DevTools will degrade gracefully for older versions of React that do not inject the new reconciler rename* or delete* methods.
Specifically, this commit includes the following changes:
* Adds unit tests (for modern and legacy renderers) to cover overriding props, renaming keys, and deleting keys.
* Refactor backend override methods to reduce redundant Bridge/Agent listeners and methods.
* Inject new (DEV-only) methods from reconciler into DevTools to rename and delete paths.
* Refactor 'inspected element' UI components to improve readability.
* Improve auto-size input to better mimic Chrome's Style editor panel. (See this Code Sandbox for a proof of concept.)
It also contains the following code cleanup:
* Additional unit tests have been added for modifying values as well as renaming or deleting paths.
* Four new DEV-only methods have been added to the reconciler to be injected into the DevTools hook: overrideHookStateDeletePath, overrideHookStateRenamePath, overridePropsDeletePath, and overridePropsRenamePath. (DevTools will degrade gracefully for older renderers without these methods.)
* I also took this as an opportunity to refactor some of the existing code in a few places:
* Rather than the backend implementing separate methods for editing props, state, hooks, and context– there are now three methods: deletePath, renamePath, and overrideValueAtPath that accept a type argument to differentiate between props, state, context, or hooks.
* The various UI components for the DevTools frontend have been refactored to remove some unnecessary repetition.
This commit also adds temporary support for override* commands with mismatched backend/frontend versions:
* Add message forwarding for older backend methods (overrideContext, overrideHookState, overrideProps, and overrideState) to the new overrideValueAtPath method. This was done in both the frontend Bridge (for newer frontends passing messages to older embedded backends) and in the backend Agent (for older frontends passing messages to newer backends). We do this because React Native embeds the React DevTools backend, but cannot control which version of the frontend users use.
* Additional unit tests have been added as well to cover the older frontend to newer backend case. Our DevTools test infra does not make it easy to write tests for the other way around.
Adds back the `TestUtils.act` implementation that I had removed
in #19745. This version of `act` is implemented in "userspace" (i.e. not
the reconciler), so it doesn't add to the production bundle size.
I had removed this in #19745 in favor of the `act` exported by the
reconciler because I thought we would remove support for `act` in
production in the impending major release. (It currently warns.)
However, we've since decided to continue supporting `act` in prod for
now, so that it doesn't block people from upgrading to v17. We'll drop
support in a future major release.
So, to avoid bloating the production bundle size, we need to move the
public version of `act` back to "userspace", like it was before.
This doesn't negate the main goal of #19745, though, which was to
decouple the public version(s) of `act` from the internal one that we
use to test React itself.
Removes the `Update` flag when scheduling a passive effect for
`useEffect`. The `Passive` flag alone is sufficient.
This doesn't affect any behavior, but does optimize the performance of
the commit phase.
In addition to `TSTypeQuery`, dependency nodes with a `TSTypeReference`
parent need to be ignored as well. Without this fix, generic type
variables will be listed as missing dependencies.
Example:
export function useFoo<T>(): (foo: T) => boolean {
return useCallback((foo: T) => false, []);
}
This will report the following issue:
React Hook useCallback has a missing dependency: 'T'. Either include
it or remove the dependency array
Closes: #19742
If there are any suspended fallbacks at the end of the `act` scope,
force them to display by running the pending timers (i.e. `setTimeout`).
The public implementation of `act` achieves the same behavior with an
extra check in the work loop (`shouldForceFlushFallbacks`). Since our
internal `act` needs to work in both development and production, without
additional runtime checks, we instead rely on Jest's mock timers.
This doesn't not affect refresh transitions, which are meant to delay
indefinitely, because in that case we exit the work loop without
posting a timer.
In the next major release, we intend to drop support for using the `act`
testing helper in production. (It already fires a warning.) The
rationale is that, in order for `act` to work, you must either mock the
testing environment or add extra logic at runtime. Mocking the testing
environment isn't ideal because it requires extra set up for the user.
Extra logic at runtime is fine only in development mode — we don't want
to slow down the production builds.
Since most people only run their tests in development mode, dropping
support for production should be fine; if there's demand, we can add it
back later using a special testing build that is identical to the
production build except for the additional testing logic.
One blocker for removing production support is that we currently use
`act` to test React itself. We must test React in both development and
production modes.
So, the solution is to fork `act` into separate public and
internal implementations:
- *public implementation of `act`* – exposed to users, only works in
development mode, uses special runtime logic, does not support partial
rendering
- *internal implementation of `act`* – private, works in both
development and productionm modes, only used by the React Core test
suite, uses no special runtime logic, supports partial rendering (i.e.
`toFlushAndYieldThrough`)
The internal implementation should mostly match the public
implementation's behavior, but since it's a private API, it doesn't have
to match exactly. It works by mocking the test environment: it uses a
mock build of Scheduler to flush rendering tasks, and Jest's mock timers
to flush Suspense placeholders.
---
In this first commit, I've added the internal forks of `act` and
migrated our tests to use them. The public `act` implementation is
unaffected for now; I will leave refactoring/clean-up for a later step.
* Bug: Effect clean up when deleting suspended tree
Adds a failing unit test.
* Re-use static flags from suspended primary tree
When switching to a Suspense boundary's fallback, we need to be sure
to preserve static subtree flags from the primary tree.
Because the `subtreeFlags` is the union of all the flags present in
a subtree, we can use the same type as `flags`.
One practical benefit is that we can bubble up the flags from the
children with a single `|=` operator.
Structurally, everything else about the effect algorithm is unchanged.
Changes the expiration time of input updates from 1000ms to 250ms, to
match the corresponding constant in Scheduler.js.
When we made it larger, a product metric in www regressed, suggesting
there's a user interaction that's being starved by a series of
synchronous updates. If that theory is correct, the proper solution is
to fix the starvation. However, this scenario supports the idea that
expiration times are an important safeguard when starvation does happen.
Also note that, in the case of user input specifically, this will soon
no longer be an issue because we plan to make user input synchronous by
default (until you enter `startTransition`, of course.)
If weren't planning to make these updates synchronous soon anyway, I
would probably make this number a configurable parameter.
* Move preprocessData into a web worker
* Add UI feedback for loading/import error states
* Terminate worker when done handling profile
* Add display density CSS variables
* added a checkbox which appears to the right of a value when value is boolean
* checkbox with toggle capability created for boolean props
Co-authored-by: Brian Vaughn <brian.david.vaughn@gmail.com>
* Add failing tests for passive effects cleanup not being called for memoized components
* Bubble passive static subtreeTag even after bailout
This prevents subsequent unmounts from skipping over any pending passive effect destroy functions