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
* Add babel parser which supports ChainExpression
* Add and fix tests for new babel eslint parser
* extract function to mark node
* refactor for compatibility with eslint v7.7.0+
* Update eslint to v7.7.0
Update hook test since eslint now supports nullish coalescing
The `startTransition` method returned from `useTransition` is a stable
method, like `dispatch` or `setState`. You should not have to specify
it as a hook dependency.
* Use gate pragma instead of if (__EXPERIMENTAL__)
* Fix stream error handling in tests
Added an error listener so that the tests fail within their Jest scope,
instead of crashing the whole process.
And `useDeferredValue`.
The options were already disabled in previous commits, so this doesn't
change any behavior. I upated type signatures and cleaned up the hook
implementation a bit — no longer have to wrap the `start` method with
`useCallback`, because its only remaining dependency is a `setState`
method, which never changes. Instead, we can store the `start` method
on a ref.
Now that the options in SuspenseConfig are no longer supported, the
only thing we use it for is to track whether an update is part of
a transition.
I've renamed `ReactCurrentBatchConfig.suspense` to
`ReactCurrentBatchConfig.transition`, and changed the type to a number.
The number is always either 0 or 1. I could have made it a boolean;
however, most likely this will eventually be either a Lane or an
incrementing identifier.
The `withSuspenseConfig` export still exists until we've removed
all the callers from www.
* Disable busyDelayMs and busyMinDurationMs
Refer to explanation in previous commit.
* Remove unnecessary work loop variables
Since we no longer support SuspenseConfig options, we don't need to
track these values.
* Remove unnecessary Update fields
* Remove distinction between long, short transitions
We're removing the `timeoutMs` option, so there's no longer any
distinction between "short" and "long" transitions. They're all treated
the same.
This commit doesn't remove `timeoutMs` yet, only combines the internal
priority levels.
* Disable `timeoutMs` argument
tl;dr
-----
- We're removing the `timeoutMs` argument from `useTransition`.
- Transitions will either immediately switch to a skeleton/placeholder
view (when loading new content) or wait indefinitely until the data
resolves (when refreshing stale content).
- This commit disables the `timeoutMS` so that the API has the desired
semantics. It doesn't yet update the types or migrate all the test
callers. I'll do those steps in follow-up PRs.
Motivation
----------
Currently, transitions initiated by `startTransition` / `useTransition`
accept a `timeoutMs` option. You can use this to control the maximum
amount of time that a transition is allowed to delay before we give up
and show a placeholder.
What we've discovered is that, in practice, every transition falls into
one of two categories: a **load** or a **refresh**:
- **Loading a new screen**: show the next screen as soon as possible,
even if the data hasn't finished loading. Use a skeleton/placeholder
UI to show progress.
- **Refreshing a screen that's already visible**: keep showing the
current screen indefinitely, for as long as it takes to load the fresh
data, even if the current data is stale. Use a pending state (and
maybe a busy indicator) to show progress.
In other words, transitions should either *delay indefinitely* (for a
refresh) or they should show a placeholder *instantly* (for a load).
There's not much use for transitions that are delayed for a
small-but-noticeable amount of time.
So, the plan is to remove the `timeoutMs` option. Instead, we'll assign
an effective timeout of `0` for loads, and `Infinity` for refreshes.
The mechanism for distinguishing a load from a refresh already exists in
the current model. If a component suspends, and the nearest Suspense
boundary hasn't already mounted, we treat that as a load, because
there's nothing on the screen. However, if the nearest boundary is
mounted, we treat that as a refresh, since it's already showing content.
If you need to fix a transition to be treated as a load instead of a
refresh, or vice versa, the solution will involve rearranging the
location of your Suspense boundaries. It may also involve adding a key.
We're still working on proper documentation for these patterns. In the
meantime, please reach out to us if you run into problems that you're
unsure how to fix.
We will remove `timeoutMs` from `useDeferredValue`, too, and apply the
same load versus refresh semantics to the update that spawns the
deferred value.
Note that there are other types of delays that are not related to
transitions; for example, we will still throttle the appearance of
nested placeholders (we refer to this as the placeholder "train model"),
and we may still apply a Just Noticeable Difference heuristic (JND) in
some cases. These aren't going anywhere. (Well, the JND heuristic might
but for different reasons than those discussed above.)
* ensure getDisplayName is only called on functions
* add SuspenseList to Dev tools element names
* Add SuspenseList and pass tests
* Import SuspenseList directly
* run prettier
* Refactor tests to use real components
* run linter
* Lint rule to forbid access of cross-fork fields
We use a shared Fiber type for both reconciler forks (old and new). It
is a superset of all the fields used by both forks. However, there are
some fields that should only be used in the new fork, and others that
should only be used in the old fork.
Ideally we would enforce this with separate Flow types for each fork.
The problem is that the Fiber type is accessed by some packages outside
the reconciler (like React DOM), and get passed into the reconciler as
arguments. So there's no way to fork the Fiber type without also forking
the packages where they are used. FiberRoot has the same issue.
Instead, I've added a lint rule that forbids cross-fork access of
fork-specific fields. Fields that end in `_old` or `_new` are forbidden
from being used inside the new or old fork respectively. Or you can
specific custom fields using the ESLint plugin options.
I used this plugin to find and remove references to the effect list
in d2e914a.
* Mark effect list fields as old
And `subtreeTag` as new.
I didn't mark `lastEffect` because that name is also used by the
Hook type. Not super important; could rename to `lastEffect_old` but
idk if it's worth the effort.
* Failing test for #19608
* Attach Listeners Eagerly to Roots and Portal Containers
* Forbid createEventHandle with custom events
We can't support this without adding more complexity. It's not clear that this is even desirable, as none of our existing use cases need custom events. This API primarily exists as a deprecation strategy for Flare, so I don't think it is important to expand its support beyond what Flare replacement code currently needs. We can later revisit it with a better understanding of the eager/lazy tradeoff but for now let's remove the inconsistency.
* Reduce risk by changing condition only under the flag
Co-authored-by: koba04 <koba0004@gmail.com>
* Remove `firstEffect` null check
This is the last remaining place where the effect list has semantic
implications.
I've replaced it with a check of `effectTag` and `subtreeTag`, to see
if there are any effects in the whole tree. This matches the semantics
of the old check. However, I think only reason this optimization exists
is because it affects profiling. We should reconsider whether this
is necessary.
* Remove remaining references to effect list
We no longer use the effect list anywhere in our implementation. It's
been replaced by a recursive traversal in the commit phase.
This removes all references to the effect list in the new fork.