This is done so that any effects scheduled by the shallow render are thrown away.
Unlike the code this was forked from (in ReactComponentStackFrame) DevTools should override the dispatcher even when DevTools is compiled in production mode, because the app itself may be in development mode and log errors/warnings.
* Deprecate old test script commands
* Update PR template test script
* Add test-stable and test-www-classic
* Update circle test names
* Rename test-www-classic to test-classic
* Missed some job renames
* Missed some more job renames
* update all facebook.github.io links
* facebookincubator links : update some outdated links and fix two other broken links where they are actually the latest updated ones
* Improve error message by expanding the object in question
* Don't warn for key/ref getters
* Error if refs are passed in server components or to client components
<time> tag has been supported by Chrome since Chrome 62.0.
Remove workarounds which were in place to avoid friction with
versions before Chrome 62.
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Technically this change is unnecessary, since the feature is controlled by a flag, but since we decided not to ship this in v17– I'm going to remove it for now entirely.
When a link opens a URL in a new tab with target="_blank", it is very simple for the opened page to change the location of the original page because the JavaScript variable window.opener is not null and thus "window.opener.location can be set by the opened page. This exposes the user to very simple phishing attacks.
Adds a new prop to the Suspense component type,
`unstable_expectedLoadTime`. The presence of this prop indicates that
the content is computationally expensive to render.
During the initial mount, React will skip over expensive trees by
rendering a placeholder — just like we do with trees that are waiting
for data to resolve. That will help unblock the initial skeleton for the
new screen. Then we will continue rendering in the next commit.
For now, while we experiment with the API internally, any number passed
to `unstable_expectedLoadTime` will be treated as "computationally
expensive", no matter how large or small. So it's basically a boolean.
The reason it's a number is that, in the future, we may try to be clever
with this additional information. For example, SuspenseList could use
it as part of its heuristic to determine whether to keep rendering
additional rows.
Background
----------
Much of our early messaging and research into Suspense focused on its
ability to throttle the appearance of placeholder UIs. Our theory was
that, on a fast network, if everything loads quickly, excessive
placeholders will contribute to a janky user experience. This was backed
up by user research and has held up in practice.
However, our original demos made an even stronger assertion: not only is
it preferable to throttle successive loading states, but up to a certain
threshold, it’s also preferable to remain on the previous screen; or in
other words, to delay the transition.
This strategy has produced mixed results. We’ve found it works well for
certain transitions, but not for all them. When performing a full page
transition, showing an initial skeleton as soon as possible is crucial
to making the transition feel snappy. You still want throttle the nested
loading states as they pop in, but you need to show something on the new
route. Remaining on the previous screen can make the app feel
unresponsive.
That’s not to say that delaying the previous screen always leads to a
bad user experience. Especially if you can guarantee that the delay is
small enough that the user won’t notice it. This threshold is a called a
Just Noticeable Difference (JND). If we can stay under the JND, then
it’s worth skipping the first placeholder to reduce overall thrash.
Delays that are larger than the JND have some use cases, too. The main
one we’ve found is to refresh existing data, where it’s often preferable
to keep stale content on screen while the new data loads in the
background. It’s also useful as a fallback strategy if something
suspends unexpectedly, to avoid hiding parts of the UI that are already
visible.
We’re still in the process of optimizing our heuristics for the most
common patterns. In general, though, we are trending toward being more
aggressive about prioritizing the initial skeleton.
For example, Suspense is usually thought of as a feature for displaying
placeholders when the UI is missing data — that is, when rendering is
bound by pending IO.
But it turns out that the same principles apply to CPU-bound
transitions, too. It’s worth deferring a tree that’s slow to render if
doing so unblocks the rest of the transition — regardless of whether
it’s slow because of missing data or because of expensive CPU work.
We already take advantage of this idea in a few places, such as
hydration. Instead of hydrating server-rendered UI in a single pass,
React splits it into chunks. It can do this because the initial HTML
acts as its own placeholder. React can defer hydrating a chunk of UI as
long as it wants until the user interacts it. The boundary we use to
split the UI into chunks is the same one we use for IO-bound subtrees:
the <Suspense /> component.
SuspenseList does something similar. When streaming in a list of items,
it will occasionally stop to commit whatever items have already
finished, before continuing where it left off. It does this by showing a
placeholder for the remaining items, again using the same <Suspense />
component API, even if the item is CPU-bound.
Unresolved questions
--------------------
There is a concern that showing a placeholder without also loading new
data could be disorienting. Users are trained to believe that a
placeholder signals fresh content. So there are still some questions
we’ll need to resolve.
Commit phase durations (layout and passive) are stored on the nearest (ancestor) Profiler and bubble up during the commit phase. This bubbling used to be implemented by traversing the return path each time we finished working on a Profiler to find the next nearest Profiler.
This commit removes that traversal. Instead, we maintain a stack of nearest Profiler ancestor while recursing the tree. This stack is maintained in the work loop (since that's where the recursive functions are) and so bubbling of durations has also been moved from commit-work to the work loop.
This PR also refactors the methods used to recurse and apply effects in preparation for the new Offscreen component type.
This PR double invokes effects in __DEV__ mode.
We are thinking about unmounting layout and/or passive effects for a hidden tree. To understand potential issues with this, we want to double invoke effects. This PR changes the behavior in DEV when an effect runs from create() to create() -> destroy() -> create(). The effect cleanup function will still be called before the effect runs in both dev and prod. (Note: This change is purely for research for now as it is likely to break real code.)
**Note: The change is fully behind a flag and does not affect any of the code on npm.**
* 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
* 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.
* Add html_all_collection type to correct typeof document.all
* process HTMLAllCollection like HTMLElement + fix flow issue
* fix lint
* move flow fix comment
* Make it work with iframes too
* optimize how we get html_all_collection type
* use once Object.prototype.toString.call
* Use Retry lane for resuming CPU suspended work
* Use a global render timeout for CPU suspense heuristics
* Fix profiler test since we're now reading time more often
* Sync to new reconciler
* Test synchronously rerendering should not render more rows
* Add flow to SyntheticEvent
* Minimal implementation of known and unknown synthetic events
* less casting
* Update EnterLeaveEventPlugin.js
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
We use safelyCallDestroy for commitUnmount and passive effects unmounts but we call destroy directly in commitHookEffectListUnmount (AKA layout effects unmounts because we don't use this anywhere else). This PR changes the direct destroy call to safelyCallDestroy for consistency
The behavior of error boundaries for passive effects that throw during cleanup was recently changed so that React ignores boundaries which are also unmounting in favor of still-mounted boundaries. This commit implements that same behavior for layout effects (useLayoutEffect, componentWillUnmount, and ref-detachment).
The new, skip-unmounting-boundaries behavior is behind a feature flag (`skipUnmountedBoundaries`).
A passive effect's cleanup function may throw after an unmount. Prior to this commit, such an error would be ignored. (React would not notify any error boundaries.) After this commit, React's behavior varies depending on which reconciler fork is being used.
For the old reconciler, React will call componentDidCatch for the nearest unmounted error boundary (if there is one). If there are no unmounted error boundaries, React will still swallow the error because the return pointer has been disconnected, so the normal error handling logic does not know how to traverse the tree to find the nearest still-mounted ancestor.
For the new reconciler, React will skip any unmounted boundaries and look for a still-mounted boundary. If one is found, it will call getDerivedStateFromError and/or componentDidCatch (depending on the type of boundary).
Tests have been added for both reconciler variants for now.
These stacks improve the profiler data but they're expensive to generate and generating them can also cause runtime errors in larger applications (although an exact repro has been hard to nail down). Removing them for now. We can revisit adding them after this profiler has been integrated into the DevTools extension and we can generate them lazily.
No longer need this, since we have starvation protection in userspace.
This will also allow us to remove the concept from the Scheduler
package, which is nice because `postTask` doesn't currently support it.
`shouldYield` will currently return `true` if there's a higher priority
task in the Scheduler queue.
Since we yield every 5ms anyway, this doesn't really have any practical
benefit. On the contrary, the extra checks on every `shouldYield` call
are wasteful.
* [eslint-plugin-react-cooks] Report constant constructions
The dependency array passed to a React hook can be thought of as a list of cache keys. On each render, if any dependency is not `===` its previous value, the hook will be rerun. Constructing a new object/array/function/etc directly within your render function means that the value will be referentially unique on each render. If you then use that value as a hook dependency, that hook will get a "cache miss" on every render, making the dependency array useless.
This can be especially dangerous since it can cascade. If a hook such as `useMemo` is rerun on each render, not only are we bypassing the option to avoid potentially expensive work, but the value _returned_ by `useMemo` may end up being referentially unique on each render causing other downstream hooks or memoized components to become deoptimized.
* Fix/remove existing tests
* Don't give an autofix of wrapping object declarations
It may not be safe to just wrap the declaration of an object, since the object may get mutated.
Only offer this autofix for functions which are unlikely to get mutated.
Also, update the message to clarify that the entire construction of the value should get wrapped.
* Handle the long tail of nodes that will be referentially unique
* Catch let/var constant constructions on initial assignment
* Trim trailing whitespace
* Address feedback from @gaearon
* Rename "assignment" to "initialization"
* Add test for a constant construction used in multiple dependency arrays
Because `postTask` returns a promise, errors inside a `postTask`
callback result in the promise being rejected.
If we don't catch those errors, then the browser will report an
"Unhandled promise rejection" error. This is a confusing message to see
in the console, because the fact that `postTask` is a promise-based API
is an implementation detail from the perspective of the developer.
"Promise rejection" is a red herring.
On the other hand, if we do catch those errors, then we need to report
the error to the user in some other way.
What we really want is the default error reporting behavior that a
normal, non-Promise browser event gets.
So, we'll re-throw inside `setTimeout`.
This updates the experimental Scheduler postTask build to call postTask
directly, instead of managing our own custom queue and work loop.
We still use a deadline 5ms mechanism to implement `shouldYield`.
The main thing that postTask is currently missing is the continuation
feature — when yielding to the main thread, the yielding task is sent
to the back of the queue, instead of maintaining its position.
While this would be nice to have, even without it, postTask may be good
enough to replace our userspace implementation.
We'll run some tests to see.
* Add ReactVersion to SchedulingProfiler render scheduled marks
* Move ReactVersion to a new --react-init-* mark
Co-authored-by: E-Liang Tan <eliang@eliangtan.com>
* Support inner component _debugOwner in memo
* test with devtool context
* remove memo test
* Merged master; tweaked test and snapshot
* Pass owner to createFiber fn when creating a memo component.
Co-authored-by: Theodore Han <tqhan317@gmail.com>
* test: Simulate mouseover in browser
* Fix duplicate onMouseEnter event when relatedTarget is a root
* Test leave as well
Co-authored-by: Sebastian Silbermann <silbermann.sebastian@gmail.com>
* test: Add current behavior for event types of onFocus/onBlur
* fix: onFocus/onBlur have a matching event type
* fix useFocus
* fix: don't compare native event types with react event types
* Add FocusIn/FocusOutEventInterface
* A simpler alternative fix
* Add regression tests
* Always pass React event type and fix beforeinput
Co-authored-by: Dan Abramov <dan.abramov@me.com>
A passive effect's cleanup function may throw after an unmount. In that event, React sometimes threw an uncaught runtime error trying to access a property on a null stateNode field. This commit fixes that (and adds a regression test).
* Get current time from performance.now in non-DOM environments
* Use local references to native APIs for Date and Performance
* Refactored to read globals directly
* Test: Don't unmount siblings of deleted node
Adds a failing regression test. Will fix in the next commit.
* Refactor to accept deleted fiber, not child list
A deleted fiber is passed to
flushPassiveUnmountEffectsInsideOfDeletedTree, but the code is written
as if it accepts the first node of a child list. This is likely because
the function was based on similar functions like
`flushPassiveUnmountEffects`, which do accept a child list.
Unfortunately, types don't help here because we use the first node
in the list to represent the whole list, so in both cases, the type
is Fiber.
Might be worth changing the other functions to also accept individual
fibers instead of a child list, to help avoid confusion.
* Add layout effect to regression test, just in case
Creates new subtree tag, PassiveStatic, that represents whether a
tree contains any passive effect hooks.
It corresponds to the PassiveStatic effect tag, which represents the
same concept for an individual fiber.
This allows us to remove the PassiveStatic effect tag from PassiveMask.
Its presence was causing us to schedule a passive effect phase callback
on every render, instead of only when something changed. That's now
fixed; this is reflected in the SchedulerProfiler tests.
(The naming is getting really confusing. Need to do some bikeshedding.)
* setCurrentFiber per fiber, instead of per effect
* Re-use safelyCallDestroy
Part of the code in flushPassiveUnmountEffects is a duplicate of the
code used for unmounting layout effects. I did some minor refactoring to
so we could use the same function in both places.
Closure will inline anyway so it doesn't affect code size or
performance, just maintainability.
* Don't check HookHasEffect during deletion
We don't need to check HookHasEffect during a deletion; all effects are
unmounted.
So we also don't have to set HookHasEffect during a deletion, either.
This allows us to remove the last remaining passive effect logic from
the synchronous layout phase.
* Remove opaque event type
* Rename type and merge files
* Use literals where we have Flow coverage
* Flowify some plugins
* Remove constants except necessary ones
The root fiber doesn't have a parent from which we can read the
`subtreeTag`, so we need to check its `effectTag` directly.
The root fiber previously did not have any pending passive effects,
but it does now that deleted fibers are cleaned up in the passive phase.
This allows us to remove a `schedulePassiveEffectCallback` call from the
synchronous unmount path.
Co-authored-by: Brian Vaughn <bvaughn@fb.com>
Saves us from having to set a flag on `current` during the layout phase.
Could result in some redundant traversal, since PassiveStatic includes
effects that don't need clean-up. But it's worth it to remove the work
from the layout phase.
While I was editing this, I also re-arranged it so that we check the
`effectTag` check before we check the `tag`, since the `effectTag` check
is the one that's more likely to fail.
* Adds new `Passive` subtree tag value.
* Adds recursive traversal for passive effects (mounts and unmounts).
* Removes `pendingPassiveHookEffectsMount` and `pendingPassiveHookEffectsUnmount` arrays from work loop.
* Re-adds sibling and child pointer detaching (temporarily removed in previous PR).
* Addresses some minor TODO comments left over from previous PRs.
---
Co-authored-by: Luna Ruan <luna@fb.com>
* Reduce code to necessities
* Switch to postTask API
* Add SchedulerPostTask tests
* Updates from review
* Fix typo from review
* Generate build of unstable_post_task
* Add "unstbale_" prefix to mutable source APIs
* DebugHooks no longer calls useMutableSource() on init
This was causing an observable behavioral difference between experimental DEV and PROD builds.
We don't initialize stack position for other composite hooks (e.g. useDeferredValue, useTransition, useOpaqueIdentifier). If we did, it would cause the same obesrvable behavioral difference.
Tasks with SyncBatchedPriority — used by Blocking Mode — should always
be rendered by the `peformSyncWorkOnRoot` path, not
`performConcurrentWorkOnRoot`.
Currently, they go through the `performConcurrentWorkOnRoot` callback.
Then, we check `didTimeout` to see if the task expired. Since
SyncBatchedPriority translates to ImmediatePriority in the Scheduler,
`didTimeout` is always `true`, so we mark it as expired. Then it exits
and re-enters in the `performSyncWorkOnRoot` path.
Aside from being overly convoluted, we shouldn't rely on Scheduler to
tell us that SyncBatchedPriority work is synchronous. We should handle
that ourselves.
This will allow us to remove the `didTimeout` check. And it further
decouples us from the Scheduler priority, so we can eventually remove
that, too.
The old expiration times implementation used this field to infer when
the priority of a task had changed at a more granular level than a
Scheduler priority level.
Now that we have the LanePriority type, which is React-specific, we no
longer need the `callbackId` field.
Since the Lanes refactor landed, we no longer rely on this anywhere, so
we can remove it.
The `delay` option is still needed by our timer implementation
(setTimeout polyfill). We'll keep the feature, but we'll likely change
how it's exposed once we figure out the proper layering between the
various Scheduler APIs.
Persistent mode needs to clone a parent and add its children if a child has
changed.
We have an optimization in persistent mode where we don't do that if no
child could've changed. If there are no effects scheduled for any child
then there couldn't have been changes.
Instead of checking for this on firstEffect, we now check this on the
children's effectTag and subtreeTags.
This is quite unfortunate because if we could just do this check a little
bit later we would've already gotten it transferred to the completed work's
subtreeTag. Now we have to loop over all the children and if any of them
changed, we have to loop over them again. Doing at least two loops per
parent.
* Remove capturePhaseEvents and separate events by bubbling
WIP
Refine all logic
Revise types
Fix
Fix conflicts
Fix flags
Fix
Fix
Fix test
Revise
Cleanup
Refine
Deal with replaying
Fix
* Add non delegated listeners unconditionally
* Add media events
* Fix a previously ignored test
* Address feedback
Co-authored-by: Dan Abramov <dan.abramov@me.com>
* Pass event time to markRootUpdated
Some minor rearranging so that eventTime gets threaded through. No
change in behavior.
* Track event times per lane on the root
Previous strategy was to store the event time on the update object
and accumulate the most recent one during the render phase.
Among other advantages, by tracking them on the root, we can read the
event time before the render phase has finished.
I haven't removed the `eventTime` field from the update object yet,
because it's still used to compute the timeout. Tracking the timeout
on the root is my next step.
* Set current update lane priority for user blocking events
* Update to use LanePriority and not use runWithPriority
* Remove unused imports
* Fix tests, and I missed ReactDOMEventListener
* Fix more tests
* Add try/finally and hardcode lane priorities instead
* Also hard code InputContinuousLanePriority in tests
* Remove un-needed exports
* Comment rollbacks
* Make enableSchedulingProfiler flag static
* Copied debug tracing and scheduler profiling to .new fork and updated feature flags
* Move profiler component stacks behind a feature flag
* Effects list rewrite
* Improved deletions approach
Process deletions as we traverse the tree during commit, before we process other effects. This has the result of better mimicking the previous sequencing.
* Made deletions field nullable
* Revert (no longer necessary) change to ReactNative test
* Eagerly set Deletions effect on Fiber when adding child to deletions array
* Initialize deletions array to null
* Null out deletions array instead of splicing 🤡
* Removed TODO comment
* Initial exploration on a did-bailout flag
* fixed the rest of the bugs
* Rolled temporary didBailout attribute into subtreeTag
* addressed comments
* Removed DidBailout subtree tag
* Removed stale comment
* use while loop instead of recursion for siblings
* move bailout flag from while loop
* Removed some unnecessary Deletion effectTags from children
* Move Deletion effect assignment to deletions array initialization
Co-authored-by: Luna <lunaris.ruan@gmail.com>
DevTools isn't being downloaded like typical JavaScript, so bundle size concerns don't apply. Parsing is still a consideration (so I'm open for discussion here) but I think this change would provide a couple of benefits:
* People are more likely to *actually read* non-minified source code when e.g. a breakpoint is hit (as with the recent debugger statement)
* Component stacks will be easier to parse on bug reports
* Make enableSchedulingProfiler static for profiling+experimental builds
* Copied debug tracing and scheduler profiling to .new fork
* Updated test @gate conditions
Now that Suspense retries have their own dedicated set of lanes
(#19287), we can determine if a render includes only retries by checking
if its lanes are a subset of the retry lanes.
Previously we inferred this by checking
`workInProgressRootLatestProcessedEventTime`. If it's not set, that
implies that no updates were processed in the current render, which
implies it must be a Suspense retry. The eventual plan is to get rid of
`workInProgressRootLatestProcessedEventTime` and instead track event
times on the root; this change is one the steps toward that goal.
The relevant tests were originally added in #15769.
Some clean up to make the Lanes type easier to maintain.
I removed the "start" and "end" range markers; they don't provide any
information that isn't already encoded in the bitmask for each range,
and there's no computation saved compared to the
`pickArbitraryLane` function.
The overall algorithm is largely the same but I did tweak some of the
details. For example, if the lanes for a given priority are already
being worked on, the previous algorithm would assign to the next
available lane, including the dedicated hydration lanes that exist
in between each priority.
The updated algorithm skips over the hydration lanes and goes to the
next priority level. In the rare instance when all the non-Idle update
lanes are occupied, it will pick an abitrary default lane. This will
have the effect of invalidating the current work-in-progress, and
indicates a starvation scenario.
Eventually, if there are too many interruptions, the expiration time
mechanism will kick in and force the update to synchronously finish.
A "retry" is a special type of update that attempts to flip a Suspense
boundary from its placeholder state back to its primary/resolved state.
Currently, retries are given default priority, using the same algorithm
as normal updates and occupying range of lanes.
This adds a new range of lanes dedicated specifically to retries, and
gives them lower priority than normal updates.
A couple of existing tests were affected because retries are no longer
batched with normal updates; they commit in separate batches.
Not totally satisfied with this design, but I think things will snap more
into place once the rest of the Lanes changes (like how we handle
parallel Suspense transitions) have settled.
High level breakdown of this commit:
* Add a enableSchedulingProfiling feature flag.
* Add functions that call User Timing APIs to a new SchedulingProfiler file. The file follows DebugTracing's structure.
* Add user timing marks to places where DebugTracing logs.
* Add user timing marks to most other places where @bvaughn's original draft DebugTracing branch marks.
* Tests added
* More context (and discussions with @bvaughn) available at our internal PR MLH-Fellowship#11 and issue MLH-Fellowship#5.
Similar to DebugTracing, we've only added scheduling profiling calls to the old reconciler fork.
Co-authored-by: Kartik Choudhary <kartik.c918@gmail.com>
Co-authored-by: Kartik Choudhary <kartikc.918@gmail.com>
Co-authored-by: Brian Vaughn <brian.david.vaughn@gmail.com>
* add unit test asserting internal hooks state is reset
* Reset internal hooks state before rendering
* reset hooks state on error
* Use expect...toThrow instead of try/catch in test
* reset dev-only hooks state inside resetHooksState
* reset currentlyRenderingComponent to null
* Rename internal variables
This disambiguates "optional"/"required" because that terminology is taken by optional chaining.
* Handle optional member chains
* Update comment
Co-authored-by: Ricky <rickhanlonii@gmail.com>
Co-authored-by: Ricky <rickhanlonii@gmail.com>
* Revert "Fix ExhaustiveDeps ESLint rule throwing with optional chaining (#19260)"
This reverts commit 0f84b0f02b.
* Re-add a test from #19260
* Remove all code for optional chaining support
* Consistently treat optional chaining as regular chaining
This is not ideal because our suggestions use normal chaining. But it gets rid of all current edge cases.
* Add more tests
* More consistency in treating normal and optional expressions
* Add regression tests for every occurrence of Optional*
* Initial currentLanePriority implementation
* Minor updates from review
* Fix typos and enable flag
* Fix feature flags and lint
* Fix simple event tests by switching to withSuspenseConfig
* Don't lower the priority of setPending in startTransition below InputContinuous
* Move currentUpdateLanePriority in commit root into the first effect block
* Refactor requestUpdateLane to log for priority mismatches
Also verifies that the update lane priority matches the scheduler lane priority before using it
* Fix four tests by adding ReactDOM.unstable_runWithPriority
* Fix partial hydration when using update lane priority
* Fix partial hydration when using update lane priority
* Rename feature flag and only log for now
* Move unstable_runWithPriority to ReactFiberReconciler
* Add unstable_runWithPriority to ReactNoopPersistent too
* Bug fixes and performance improvements
* Initial currentLanePriority implementation
* Minor updates from review
* Fix typos and enable flag
* Remove higherLanePriority from ReactDOMEventReplaying.js
* Change warning implementation and startTransition update lane priority
* Inject reconciler functions to avoid importing src/
* Fix feature flags and lint
* Fix simple event tests by switching to withSuspenseConfig
* Don't lower the priority of setPending in startTransition below InputContinuous
* Move currentUpdateLanePriority in commit root into the first effect block
* Refactor requestUpdateLane to log for priority mismatches
Also verifies that the update lane priority matches the scheduler lane priority before using it
* Fix four tests by adding ReactDOM.unstable_runWithPriority
* Fix partial hydration when using update lane priority
* Fix partial hydration when using update lane priority
* Rename feature flag and only log for now
* Move unstable_runWithPriority to ReactFiberReconciler
* Bug fixes and performance improvements
* Remove higherLanePriority from ReactDOMEventReplaying.js
* Change warning implementation and startTransition update lane priority
* Inject reconciler functions to avoid importing src/
* Fixes from bad rebase
Certain code patterns using optional chaining syntax causes
eslint-plugin-react-hooks to throw an error.
We can avoid the throw by adding some guards. I didn't read through the
code to understand how it works, I just added a guard to every place
where it threw, so maybe there is a better fix closer to the root cause
than what I have here.
In my test case, I noticed that the optional chaining that was used in
the code was not included in the suggestions description or output,
but it seems like it should be. This might make a nice future
improvement on top of this fix, so I left a TODO comment to that effect.
Fixes#19243
* Add a failing test for legacy Suspense blocking context updates in memo
* Add more test case coverage for variations of #17356
* Don't bailout after Suspending in Legacy Mode
Co-authored-by: Tharuka Devendra <tsdevendra1@gmail.com>
* Add new test cli
* Remove --variant accidentally added to test-persist
* s/test/tests
* Updates from review
* Update package.json tests
* Missed a release channel in circle.yaml
* Update config.yml to use just run: with test commands
* Update release-channel options and add build dir checks
* Update test args to use the new release-channel options
* Fix error in circle config.yml
* Fix a wrong condition for the --variant check
* Fix a wrong condition for the --persistent check
* Prettier
* Require build check for devtool tests as well
* Re-enabled DebugTracing feature for old reconciler fork
It was temporarily removed by @sebmarkbage via PR #18697. Newly re-added tracing is simplified, since the lane(s) data type does not require the (lossy) conversion between priority and expiration time values.
@sebmarkbage mentioned that he removed this because it might get in the way of his planned discrete/sync refactor. I'm not sure if that concern still applies, but just in case- I have only re-added it to the old reconciler fork for now.
* Force Code Sandbox CI to re-run
DevTools has a feature to force a Suspense boundary to show a fallback.
This feature causes us to skip the first render pass (where we render
the primary children) and go straight to rendering the fallback.
There's a Legacy Mode-only codepath that failed to take this scenario
into account, instead assuming that whenever a fallback is being
rendered, it was preceded by an attempt to render the primary children.
SuspenseList can also cause us to skip the first pass, but the relevant
branch is Legacy Mode-only, and SuspenseList is not supported in
Legacy Mode.
Fixes a test that I had temporarily disabled when upstreaming the Lanes
implementation in #19108.
It was temporarily removed by @sebmarkbage via PR #18697. Newly re-added tracing is simplified, since the lane(s) data type does not require the (lossy) conversion between priority and expiration time values.
@sebmarkbage mentioned that he removed this because it might get in the way of his planned discrete/sync refactor. I'm not sure if that concern still applies, but just in case- I have only re-added it to the old reconciler fork for now.
* Add autofix to cross-fork lint rule
* replace-fork: Replaces old fork contents with new
For each file in the new fork, copies the contents into the
corresponding file of the old fork, replacing what was already there.
In contrast to merge-fork, which performs a three-way merge.
* Replace old fork contents with new fork
First I ran `yarn replace-fork`.
Then I ran `yarn lint` with autofix enabled. There's currently no way to
do that from the command line (we should fix that), so I had to edit the
lint script file.
* Manual fix-ups
Removes dead branches, removes prefixes from internal fields. Stuff
like that.
* Fix DevTools tests
DevTools tests only run against the old fork, which is why I didn't
catch these earlier.
There is one test that is still failing. I'm fairly certain it's related
to the layout of the Suspense fiber: we no longer conditionally wrap the
primary children. They are always wrapped in an extra fiber.
Since this has been running in www for weeks without major issues, I'll
defer fixing the remaining test to a follow up.
* Failing test: Infinite loop in beforeblur event
If the focused node is hidden by a Suspense boundary, we fire the
beforeblur event. Our check for whether a tree is being hidden isn't
specific enough. It should only fire when the tree is initially hidden,
but it's being fired for updates, too.
* Only fire beforeblur on visible -> hidden
Should only beforeblur fire if the node was previously visible. Not
during updates to an already hidden tree.
To optimize this, we should use a dedicated effect tag and mark it in
the render phase. I've left this for a follow-up, though. Maybe can
revisit after the planned refactor of the commit phase.
* Move logic to commit phase
isFiberSuspenseAndTimedOut is used elsewhere, so I inlined the commit
logic into the commit phase itself.
We need this so we can version them separately and use different
feature flags than we use for OSS RN.
I put them in a separate facebook-react-native folder which won't go
into the RN GH repo. I plan on moving the renderers there too but not yet.
This commit adds a new tab to the Settings modal: Debugging
This new tab has the append component stacks feature and a new one: break on warn
This new feature adds a debugger statement into the console override
This was originally added so you could use "break on caught exceptions"
but that feature is pretty useless these days since it's used for feature
detection and Suspense.
The better pattern is to use the stack trace, jump to source and set a
break point here.
Since DevTools injects its own console.error, we could inject a "debugger"
statement in there. Conditionally. E.g. React DevTools could have a flag
to toggle "break on warnings".
I accidentally committed this since I had it on locally so I didn't have
to manually convert things to const.
However, this causes things to always pass lint since CI also runs this.
I don't think we'll ever use this just because we have such a unique set up
for network delivery so we'll use something custom for this case.
Also, we don't need a profiling build for this since it doesn't have an
entry point.
* Lint bundles using the bundle config instead of scanning for files
This ensures that we look for all the files that we expect to see there.
If something doesn't get built we wouldn't detect it.
However, this doesn't find files that aren't part of our builds such as
indirection files in the root. This will need to change with ESM anyway
since indirection files doesn't work. Everything should be built anyway.
This ensures that we can use the bundles.js config to determine special
cases instead of relying on file system conventions.
* Run lint with flag
We really needed this for Flight before as well but we got away with it
because Blocks were lazy but with the removal of Blocks, we'll need this
to ensure that we can lazily stream in part of the content.
Luckily LazyComponent isn't really just a Component. It's just a generic
type that can resolve into anything kind of like a Promise.
So we can use that to resolve elements just like we can components.
This allows keys and props to become lazy as well.
To accomplish this, we suspend during reconciliation. This causes us to
not be able to render siblings because we don't know if the keys will
reconcile. For initial render we could probably special case this and
just render a lazy component fiber.
Throwing in reconciliation didn't work correctly with direct nested
siblings of a Suspense boundary before but it does now so it depends
on new reconciler.
* Gate test
* Delete entrypoints without Build Outputs from package.json and build output
If an entry point exists in bundles.js but doesn't have any bundleTypes,
I delete that entry point file from the build directory. I also remove it
from the files field in package.json if it exists.
This allows us to remove bundles from being built in the stable release
channel.
We currently prepare an extra stack frame before they're needed.
Particularly for propTypes. This causes problems as they can have
side-effects with the new component stacks and it's slow.
This moves it to be lazy.
* Bug: Spawning hydration in response to Idle update
Adds a test that fails in the new fork.
* Fix typos related to Idle priority
These are just silly mistakes that weren't caught by any of our tests.
There's a lot of duplication in the Lanes module right now. It's also
not super stable as we continue to refine our heuristics. Hopefully the
final state is simpler and less prone to these types of mistakes.
Facebook currently relies on being able to hydrate hidden HTML. So
skipping those trees is a regression.
We don't have a proper solution for this in the new API yet. So I'm
reverting it to match the old behavior.
Now the server renderer will treat LegacyHidden the same as a fragment,
with no other special behavior. We can only get away with this because
we assume that every instance of LegacyHidden is accompanied by a host
component wrapper. In the hidden mode, the host component is given a
`hidden` attribute, which ensures that the initial HTML is not visible.
To support the use of LegacyHidden as a true fragment, without an extra
DOM node, we will have to hide the initial HTML in some other way.
* Warn if MutableSource snapshot is a function
useMutableSource does not properly support snapshots that are functions. In part this is because of how it is implemented internally (the function gets mistaken for a state updater function). To fix this we could just wrap another function around the returned snapshot, but this pattern seems problematic to begin with- because the function that gets returned might itself close over mutable values, which would defeat the purpose of using the hook in the first place.
This PR proposes adding a new DEV warning if the snapshot returned is a function. It does not change the behavior (meaning that a function could still work in some cases- but at least the current behavior prevents passing around a closure that may later become stale unless you're really intentional about it e.g. () => () => {...}).
* Replaced .warn with .error
* useMutableSource hydration support
* Remove unnecessary ReactMutableSource fork
* Replaced root.registerMutableSourceForHydration() with mutableSources option
* Response to PR feedback:
1. Moved mutableSources root option to hydrationOptions object
2. Only initialize root mutableSourceEagerHydrationData if supportsHydration config is true
3. Lazily initialize mutableSourceEagerHydrationData on root object
This is a bit gross but I need to be able to access it without importing
the renderer.
There might be a better way but I need this to unblock internal bugfix.
Deferring a hidden tree is only supported in Concurrent Mode.
The missing check leads to an infinite loop when an update is scheduled
inside a hidden tree, because the pending work never gets reset.
This "accidentally" worked in the old reconciler because the heurstic
we used to detect offscreen trees was if `childExpirationTime`
was `Never`.
In the new reconciler, we check the tag instead. Which means we also
need to check the mode, like we do in the begin phase.
We should move this check out of the hot path. It shouldn't have been
in the hot path of the old reconciler, either.
Probably by moving `resetChildLanes` into the switch statement
in ReactFiberCompleteWork.
Need this to unblock www. Not sure yet how we'll support this properly
long term.
While adding this, I noticed that the normal "hidden" mode of
LegacyHidden doesn't work properly because it doesn't toggle the
visibility of newly inserted nodes. This is fine for now since we only
use it via a userspace abstraction that wraps the children in an
additional node. But implementing this correctly is required for us
to start using it like a fragment, without the wrapper node.
This package is missing the license attribute (or a license file).
Being a sub-package of React, it should get the same license, however, none was specified.
A scan with `license_checker` would recognize this as `UNKNOWN`.
* skip reading element for imported data
* rename nodes & enable store lookup for components tab
* replace names
* Added some more test coverage; reverted rename
Co-authored-by: Brian Vaughn <bvaughn@fb.com>
The function you provide will only be passed a child and an index. It will not be passed a key. This is confirmed in the source, the Flow types, and the jsdoc comments.
* Add LegacyHidden to server renderer
When the tree is hidden, the server renderer renders nothing. The
contents will be completely client rendered.
When the tree is visible it acts like a fragment.
The future streaming server renderer may want to pre-render these trees
and send them down in chunks, as with Suspense boundaries.
* Force client render, even at Offscreen pri
The motivation for doing this is to make it impossible for additional
uses of pre-rendering to sneak into www without going through the
LegacyHidden abstraction. Since this feature was already disabled in
the new fork, this brings the two closer to parity.
The LegacyHidden abstraction itself still needs to opt into
pre-rendering somehow, so rather than totally disabling the feature, I
updated the `hidden` prop check to be obnoxiously specific. Before, you
could set it to any truthy value; now, you must set it to the string
"unstable-do-not-use-legacy-hidden".
The node will still be hidden in the DOM, since any truthy value will
cause the browser to apply a style of `display: none`.
I will have to update the LegacyHidden component in www to use the
obnoxious string prop. This doesn't block merge, though, since the
behavior is gated by a dynamic flag. I will update the component before
I enable the flag.
* Failing useMutableSource test
If a source is mutated after initial read but before subscription is set
up, it should still entangle all pending mutations even if snapshot of
new subscription happens to match.
Test case illustrates how not doing this can lead to tearing.
* Fix useMutableSource tearing bug
Fix is to move the entanglement call outside of the block that checks
if the snapshot has changed.
* useMutableSource: "Entangle" instead of expiring
A lane is said to be entangled with another when it's not allowed to
render in a batch that does not also include the other lane.
This commit implements entanglement for `useMutableSource`. If a source
is mutated in between when it's read in the render phase, but before
it's subscribed to in the commit phase, we must account for whether the
same source has pending mutations elsewhere. The old subscriptions must
not be allowed to re-render without also including the new subscription
(and vice versa), to prevent tearing.
In the old reconciler, we did this by synchronously flushing all the
pending subscription updates. This works, but isn't ideal. The new
reconciler can entangle the updates without de-opting to sync.
In the future, we plan to use this same mechanism for other features,
like skipping over intermediate useTransition states.
* Use clz instead of ctrz to pick an arbitrary lane
Should be slightly faster since most engines have built-in support.
* [eslint-plugin-react-hooks] reproduce bug with a test and fix it (#18902)
Since we only reserve `-Effect` suffix, react-hooks/exhaustive-deps is
expected to succeed without warning on a custom hook which contains -Effect- in
the middle of it's name (but does NOT contain it as a suffix).
* [eslint-plugin-react-hooks] reproduced bug with a test and fix it
Since we only reserve `-Effect` suffix, react-hooks/exhaustive-deps is expected
to succeed without warning on a render helper which contains -use- in the middle
of it's name (but does NOT contain it as a prefix, since that would violate hook
naming convetion).
Co-authored-by: Boris Sergeyev <boris.sergeyev@quolab.com>
* First pass at scaffolding out the Node implementation of react-data.
While incomplete, this patch contains some changes to the react-data
package in order to start adding support for Node.
The first part of this change accounts for splitting react-data/fetch
into two discrete entries, adding (and defaulting to) the Node
implementation.
The second part is sketching out a rough approximation of `fetch` for
Node. This implementation is not complete by any means, but provides a
starting point.
* Remove NodeFetch module and put it directly into ReactDataFetchNode.
* Replaced react-data with react-fetch.
This patch shuffles around some of the scaffolding that was in
react-data in favor of react-fetch. It also removes the additional
"fetch" package in favor of something flatter.
* Tweak package organization
* Simplify and add a test
Co-authored-by: Dan Abramov <dan.abramov@me.com>
* Expose LegacyHidden type
I will use this internally at Facebook to migrate away from
<div hidden />. The end goal is to migrate to the Offscreen type, but
that has different semantics. This is an incremental step.
* Disable <div hidden /> API in new fork
Migrates to the unstable_LegacyHidden type instead. The old fork does
not support the new component type, so I updated the tests to use an
indirection that picks the correct API. I will remove this once the
LegacyHidden (and/or Offscreen) type has landed in both implementations.
* Add gated warning for `<div hidden />` API
Only exists so we can detect callers in www and migrate them to the new
API. Should not visible to anyone outside React Core team.
* Start MVP for showing inspected element key
* Add key in other places
* Add key from backend
* Remove unnecessary hydrateHelper call
* Hide copy button when no label
* Move above props
* Revert changes to InspectedElementTree.js
* Move key to left of component name
* Updated CSS
Co-authored-by: Brian Vaughn <brian.david.vaughn@gmail.com>
* Detect and prevent render starvation, per lane
If an update is CPU-bound for longer than expected according to its
priority, we assume it's being starved by other work on the main thread.
To detect this, we keep track of the elapsed time using a fixed-size
array where each slot corresponds to a lane. What we actually store is
the event time when the lane first became CPU-bound.
Then, when receiving a new update or yielding to the main thread, we
check how long each lane has been pending. If the time exceeds a
threshold constant corresponding to its priority, we mark it as expired
to force it to synchronously finish.
We don't want to mistake time elapsed while an update is IO-bound
(waiting for data to resolve) for time when it is CPU-bound. So when a
lane suspends, we clear its associated event time from the array. When
it receives a signal to try again, either a ping or an update, we assign
a new event time to restart the clock.
* Store as expiration time, not start time
I originally stored the start time because I thought I could use this
in the future to also measure Suspense timeouts. (Event times are
currently stored on each update object for this purpose.) But that
won't work because in the case of expiration times, we reset the clock
whenever the update becomes IO-bound. So to replace the per-update
field, I'm going to have to track those on the room separately from
expiration times.
There is a worry that `useOpaqueIdentifier` might run out of unique IDs if running for long enough. This PR moves the unique ID counter so it's generated per server renderer object instead. For people who render different subtrees, this PR adds a prefix option to `renderToString`, `renderToStaticMarkup`, `renderToNodeStream`, and `renderToStaticNodeStream` so identifiers can be differentiated for each individual subtree.
* Disable Profiler commit filtering
We used to filter "empty" DevTools commits, but it was error prone (see #18798). A commit may appear to be empty (no actual durations) because of component filters, but filtering these empty commits causes interaction commit indices to be off by N. This not only corrupts the resulting data, but also potentially causes runtime errors.
For that matter, hiding "empty" commits might cause confusion too. A commit *did happen* even if none of the components the Profiler is showing were involved.
* Restart flaky CI
In the new reconciler, I made a change to how render phase updates
work. (By render phase updates, I mean when a component updates
another component during its render phase. Or when a class component
updates itself during the render phase. It does not include when
a hook updates its own component during the render phase. Those have
their own semantics. So really I mean anything triggers the "`setState`
in render" warning.)
The old behavior is to give the update the same "thread" (expiration
time) as whatever is currently rendering. So if you call `setState` on a
component that happens later in the same render, it will flush during
that render. Ideally, we want to remove the special case and treat them
as if they came from an interleaved event.
Regardless, this pattern is not officially supported. This behavior is
only a fallback. The flag only exists until we can roll out the
`setState` warnning, since existing code might accidentally rely on the
current behavior.
* Don't attempt to render the children of a dehydrated Suspense boundary
The DehydratedFragment tag doesn't exist so doing so throws.
This can happen if we schedule childExpirationTime on the boundary and
bail out.
* Warn if scheduling work on a component before it is committed
* [Blocks Fixture] Add a tiny router
* Add a way to load nested entrypoint
* Only expose URL params to nested routers
* Add keys to route definitions
* [Blocks Fixture] Drop the Blocks
Adds several new experimental APIs to aid with automated testing.
Each of the methods below accepts an array of "selectors" that identifies a path (or paths) through a React tree. There are four basic selector types:
* Component: Matches Fibers with the specified React component type
* Role: Matches Host Instances matching the (explicit or implicit) accessibility role.
* Test name: Matches Host Instances with a data-testname attribute.
* Text: Matches Host Instances that directly contain the specified text.
* There is also a special lookahead selector type that enables further matching within a path (without actually including the path in the result). This selector type was inspired by the :has() CSS pseudo-class. It enables e.g. matching a <section> that contained a specific header text, then finding a like button within that <section>.
API
* findAllNodes(): Finds all Host Instances (e.g. HTMLElement) within a host subtree that match the specified selector criteria.
* getFindAllNodesFailureDescription(): Returns an error string describing the matched and unmatched portions of the selector query.
* findBoundingRects(): For all React components within a host subtree that match the specified selector criteria, return a set of bounding boxes that covers the bounds of the nearest (shallowed) Host Instances within those trees.
* observeVisibleRects(): For all React components within a host subtree that match the specified selector criteria, observe if it’s bounding rect is visible in the viewport and is not occluded.
* focusWithin(): For all React components within a host subtree that match the specified selector criteria, set focus within the first focusable Host Instance (as if you started before this component in the tree and moved focus forwards one step).
We've been shipping unprefixed experimental APIs (like `createRoot` and
`useTransition`) to the Experimental release channel, with the rationale
that because these APIs do not appear in any stable release, we're free
to change or remove them later without breaking any downstream projects.
What we didn't consider is that downstream projects might be tempted to
use feature detection:
```js
const useTransition = React.useTransition || fallbackUseTransition;
```
This pattern assumes that the version of `useTransition` that exists in
the Experimental channel today has the same API contract as the final
`useTransition` API that we'll eventually ship to stable.
To discourage feature detection, I've added an `unstable_` prefix to
all of our unstable APIs.
The Facebook builds still have the unprefixed APIs, though. We will
continue to support those; if we make any breaking changes, we'll
migrate the internal callers like we usually do. To make testing easier,
I added the `unstable_`-prefixed APIs to the www builds, too. That way
our tests can always use the prefixed ones without gating on the
release channel.
* Rename Flight to Transport
Flight is still the codename for the implementation details (like Fiber).
However, now the public package is react-transport-... which is only
intended to be used directly by integrators.
* Rename names
See PR #18796 for more information.
All of the changes I've made in this commit are behind the
`enableNewReconciler` flag. Merging this to master will not affect the
open source builds or the build that we ship to Facebook.
The only build that is affected is the `ReactDOMForked` build, which is
deployed to Facebook **behind an experimental flag (currently disabled
for all users)**. We will use this flag to gradually roll out the new
reconciler, and quickly roll it back if we find any problems.
Because we have those protections in place, what I'm aiming for with
this initial PR is the **smallest possible atomic change that lands
cleanly and doesn't rely on too many hacks**. The goal has not been to
get every single test or feature passing, and it definitely is not to
implement all the features that we intend to build on top of the new
model. When possible, I have chosen to preserve existing semantics and
defer changes to follow-up steps. (Listed in the section below.)
(I did not end up having to disable any tests, although if I had, that
should not have necessarily been a merge blocker.)
For example, even though one of the primary goals of this project is to
improve our model for parallel Suspense transitions, in this initial
implementation, I have chosen to keep the same core heuristics for
sequencing and flushing that existed in the ExpirationTimes model: low
priority updates cannot finish without also finishing high priority
ones.
Despite all these precautions, **because the scope of this refactor is
inherently large, I do expect we will find regressions.** The flip side
is that I also expect the new model to improve the stability of the
codebase and make it easier to fix bugs when they arise.
* Add test cases for support exhaustive deps ending in Effect
* Apply the exhaustive deps lint rule to any hook ending with Effect
* Add another test for supporting linting useXEffect hooks
Co-authored-by: Aaron Pettengill <aaron.pettengill@echoman.com>
Previously, we transformed
```
let Foo = styled.div``;
```
to
```
let Foo = _c1 = styled.div``;
```
and then babel-plugin-styled-components would infer `_c1` as the display name. Widen the existing case that applies to function expressions to apply to any type of variable declaration.
* Unhide Suspense trees without entanglement
When a Suspense boundary is in its fallback state, you cannot switch
back to the main content without also finishing any updates inside the
tree that might have been skipped. That would be a form of tearing.
Before we fixed this in #18411, the way this bug manifested was that a
boundary was suspended by an update that originated from a child
component (as opposed to props from a parent). While the fallback was
showing, it received another update, this time at high priority. React
would render the high priority update without also including the
original update. That would cause the fallback to switch back to the
main content, since the update that caused the tree to suspend was no
longer part of the render. But then, React would immediately try to
render the original update, which would again suspend and show the
fallback, leading to a momentary flicker in the UI.
The approach added in #18411 is, when receiving a high priority update
to a Suspense tree that's in its fallback state is to bail out, keep
showing the fallback and finish the update in the rest of the tree.
After that commits, render again at the original priority. Because low
priority expiration times are inclusive of higher priority expiration
times, this ensures that all the updates are committed together.
The new approach in this commit is to turn `renderExpirationTime` into a
context-like value that lives on the stack. Then, when unhiding the
Suspense boundary, we can push a new `renderExpirationTime` that is
inclusive of both the high pri update and the original update that
suspended. Then the boundary can be unblocked in a single render pass.
An advantage of the old approach is that by deferring the work of
unhiding, there's less work to do in the high priority update.
The key advantage of the new approach is that it solves the consistency
problem without having to entangle the entire root.
* Create internal LegacyHidden type
This only exists so we can clean up the internal implementation of
`<div hidden={isHidden} />`, which is not a stable feature. The goal
is to move everything to the new Offscreen type instead. However,
Offscreen has different semantics, so before we can remove the legacy
API, we have to migrate our internal usage at Facebook. So we'll need
to maintain both temporarily.
In this initial commit, I've only added the type. It's not used
anywhere. The next step is to use it to implement `hidden`.
* Use LegacyHidden to implement old hidden API
If a host component receives a `hidden` prop, we wrap its children in
an Offscreen fiber. This is similar to what we do for Suspense children.
The LegacyHidden type happens to share the same implementation as the
new Offscreen type, for now, but using separate types allows us to fork
the behavior later when we implement our planned changes to the
Offscreen API.
There are two subtle semantic changes here. One is that the children of
the host component will have their visibility toggled using the same
mechanism we use for Offscreen and Suspense: find the nearest host node
children and give them a style of `display: none`. We didn't used to do
this in the old API, because the `hidden` DOM attribute on the parent
already hides them. So with this change, we're actually "overhiding" the
children. I considered addressing this, but I figure I'll leave it as-is
in case we want to expose the LegacyHidden component type temporarily
to ease migration of Facebook's internal callers to the Offscreen type.
The other subtle semantic change is that, because of the extra fiber
that wraps around the children, this pattern will cause the children
to lose state:
```js
return isHidden ? <div hidden={true} /> : <div />;
```
The reason is that I didn't want to wrap every single host component
in an extra fiber. So I only wrap them if a `hidden` prop exists. In
the above example, that means the children are conditionally wrapped
in an extra fiber, so they don't line up during reconciliation, so
they get remounted every time `isHidden` changes.
The fix is to rewrite to:
```js
return <div hidden={isHidden} />;
```
I don't anticipate this will be a problem at Facebook, especially since
we're only supposed to use `hidden` via a userspace wrapper component.
(And since the bad pattern isn't very React-y, anyway.)
Again, the eventual goal is to delete this completely and replace it
with Offscreen.
* [Blocks] Use native fetch
* Use the prototype
* Support arrayBuffer() and blob()
* ctor
* Simplify
* Use an expando
* Keep a map of formats
* Unused
* Remove unnecessary second property read
* Keep it simple
* Store the original thenable
* Rename ReactCache -> ReactCacheOld
We still use it in some tests so I'm going to leave it for now. I'll start making the new one in parallel in the react package.
* Add react/unstable-cache entry point
* Add react-data entry point
* Initial implementation of cache and data/fetch
* Address review
* Root API should clear non-empty roots before mounting
Legacy render-into-subtree API removes children from a container before rendering into it. The root API did not do this previously, but just left the children around in the document.
This commit adds a new FiberRoot flag to clear a container's contents before mounting. This is done during the commit phase, to avoid multiple, observable mutations.
SuspenseList progressively renders items even if the list is CPU bound,
i.e. it isn't waiting for missing data. It does this by showing a
fallback for the remaining items, committing the items in that have
already finished, then starting a new render to continue working on
the rest.
When it schedules that subsequent render, it uses a slightly lower
priority than the current render: `renderExpirationTime - 1`.
This commit changes it to reschedule at `renderExpirationTime` instead.
I don't know what the original motivation was for bumping the expiration
time slightly lower. The comment says that the priorities of the two
renders are the same (which makes sense to me) so I imagine it was
motivated by some implementation detail. I don't think it's necessary
anymore, though perhaps it was when it was originally written. If it is
still necessary, we should write a test case that illustrates why.
Changes the internal fiber structure of the Suspense component. When a
Suspense boundary can't finish rendering and switches to a fallback, we
wrap the "primary" tree in a Fragment fiber and hide all its DOM nodes.
Then we mount the fallback tree into a separate Fragment fiber. Both
trees will render into the same parent DOM node (since React fragments
aren't part of the host tree), but the wrappers ensure that the children
in each tree are reconciled separately.
The old implementation would try to be clever and only add the fragment
wrapper when the fallback was in place, to save memory. This "worked"
but was prone to regressions, since this is the only such place in the
codebase where we wrap existing nodes in a new node. (In other words,
it's a form of reparenting, which we don't implement elsewhere).
Since the original implementation, we've also added lots of additional
requirements to the Suspense component that have led to an explosion in
complexity, like limited support in Legacy Mode (with very different
semantics) and progressive hydration.
We're planning to add even more features to the Suspense boundary, so
we're going to sacrifice a bit more memory for a simpler implementation
that is less prone to regressions.
This ended up removing a lot of weird hacks and edge cases, but there
are still plenty left over. Most of the remaining complexity is related
to Legacy mode. That's the next thing we should aim to drop support for.
Because this is a risky change, I've only changed this in the new
reconciler. It blocks some other features, but as of now we're not
planning to implement those in the old reconciler. If that changes, this
should cherry-pick to the other implementation without much effort.
* Add LanePriority type
React's internal scheduler has more priority levels than the external
Scheduler package. Let's use React as the source of truth for tracking
the priority of updates so we have more control. We'll still fall back
to Scheduler in the default case. In the future, we should consider
removing `runWithPriority` from Scheduler and replacing the valid use
cases with React-specific APIs.
This commit adds a new type, called a LanePriority to disambiguate from
the Scheduler one.
("Lane" refers to another type that I'm planning. It roughly translates
to "thread." Each lane will have a priority associated with it.)
I'm not actually using the lane anywhere, yet. Only setting stuff up.
* Remove expiration times train model
In the old reconciler, expiration times are computed by applying an
offset to the current system time. This has the effect of increasing
the priority of updates as time progresses. Because we also use
expiration times as a kind of "thread" identifier, it turns out this
is quite limiting because we can only flush work sequentially along
the timeline.
The new model will use a bitmask to represent parallel threads that
can be worked on in any combination and in any order.
In this commit, expiration times and the linear timeline are still in
place, but they are no longer based on a timestamp. Effectively, they
are constants based on their priority level.
* Stop using ExpirationTime to represent timestamps
Follow up to the previous commit. This converts the remaining places
where we were using the ExpirationTime type to represent a timestamp,
like Suspense timeouts.
* Fork Dependencies and PendingInteractionMap types
These contain expiration times
* Make ExpirationTime an opaque type
ExpirationTime is currently just an alias for the `number` type, for a
few reasons. One is that it predates Flow's opaque type feature. Another
is that making it opaque means we have to move all our comparisons and
number math to the ExpirationTime module, and use utility functions
everywhere else.
However, this is actually what we want in the new system, because the
Lanes type that will replace ExpirationTime is a bitmask with a
particular layout, and performing operations on it will involve more
than just number comparisions and artihmetic. I don't want this logic to
spread ad hoc around the whole codebase.
The utility functions get inlined by Closure so it doesn't matter
performance-wise.
I automated most of the changes with JSCodeshift, with only a few manual
tweaks to stuff like imports. My goal was to port the logic exactly to
prevent subtle mistakes, without trying to simplify anything in the
process. I'll likely need to audit many of these sites again when I
replace them with the new type, though, especially the ones
in ReactFiberRoot.
I added the codemods I used to the `scripts` directory. I won't merge
these to master. I'll remove them in a subsequent commit. I'm only
committing them here so they show up in the PR for future reference.
I had a lot of trouble getting Flow to pass. Somehow it was not
inferring the correct type of the constants exported from the
ExpirationTime module, despite being annotated correctly.
I tried converting them them to constructor functions — `NoWork`
becomes `NoWork()` — and that made it work. I used that to unblock me,
and fixed all the other type errors. Once there were no more type
errors, I tried converting the constructors back to constants. Started
getting errors again.
Then I added a type constraint everywhere a constant was referenced.
That fixed it. I also figured out that you only have to add a constraint
when the constant is passed to another function, even if the function is
annotated. So this indicates to me that it's probably a Flow bug. I'll
file an issue with Flow.
* Delete temporary codemods used in previous commit
I only added these to the previous commit so that I can easily run it
again when rebasing. When the stack is squashed, it will be as if they
never existed.
This could be used to do custom formatting of the stack trace in a way
that isn't compatible with how we use it. So we disable it while we use
it.
In theory we could call this ourselves with the result of our stack.
It would be a lot of extra production code though. My personal opinion
is that this should always be done server side instead of on the client.
We could expose a custom parser that converts it and passes it through
prepareStackTrace as structured data. That way it's external and doesn't
have to be built-in to React.
We currently use the stack to dedupe warnings in a couple of places.
This is a very heavy weight way of computing that a warning doesn't need
to be fired.
This uses parent component name as a heuristic for deduping. It's not
perfect but as soon as you fix one you'll uncover the next. It might be a
little annoying but having many logs is also annoying.
We now have no special cases for stacks. The only thing that uses stacks in
dev is the console.error and dev tools. This means that we could
externalize this completely to an console.error patching module and drop
it from being built-in to react.
The only prod/dev behavior is the one we pass to error boundaries or the
error we throw if you don't have an error boundary.
* Remove priority field from tracing
* Remove DebugTracing mode from new reconciler (temporarily)
* Run DebugTracing tests in the *other* variant so it's no on for new reconciler
* DevTools console override handles new component stack format
DevTools does not attempt to mimic the default browser console format for its component stacks but it does properly detect the new format for Chrome, Firefox, and Safari.
* Detect double stacks in the new format in tests
* Remove unnecessary uses of getStackByFiberInDevAndProd
These all execute in the right execution context already.
* Set the debug fiber around the cases that don't have an execution context
* Remove stack detection in our console log overrides
We never pass custom stacks as part of the args anymore.
* Bonus: Don't append getStackAddendum to invariants
We print component stacks for every error anyway so this is just duplicate
information.
* Upgrade fbjs-scripts
This script takes into account the NODE_ENV as part of jest cache keys.
This avoids flaky tests since we depend on different transforms in prod
and dev.
* Upgrade Fresh test to Babel 7 transform
* test: Add failing case for dangerouslySetInnerHtml=undefined
* fix: skip dangerouslySetInnerHtml warning if it's undefined
* test: add similar test that should trigger the warning
* chore: Remove redundant nullish check
* Poke yarn_test_www_variant which timed out
* test: Add smaller test for innerHTML=string to innerHTML=undefined
* Fix incorrect unmounted state update warning
We detach fibers (which nulls the field) when we commit a deletion, so any state updates scheduled between that point and when we eventually flush passive effect destroys won't have a way to check if there is a pending passive unmount effect scheduled for its alternate unless we also explicitly track this for both the current and the alternate.
This commit adds a new DEV-only effect type, `PendingPassiveUnmountDev`, to handle this case.
We typecheck the reconciler against each one of our host configs.
`yarn flow dom` checks it against the DOM renderer, `yarn flow native`
checks it against the native renderer, and so on.
To do this, we generate separate flowconfig files.
Currently, there is no root-level host config, so running Flow
directly via `flow` CLI doesn't work. You have to use the `yarn flow`
command and pick a specific renderer.
A drawback of this design, though, is that our Flow setup doesn't work
with other tooling. Namely, editor integrations.
I think the intent of this was maybe so you don't run Flow against a
renderer than you intended, see it pass, and wrongly think you fixed
all the errors. However, since they all run in CI, I don't think this
is a big deal. In practice, I nearly always run Flow against the same
renderer (DOM), and I'm guessing that's the most common workflow for
others, too.
So what I've done in this commit is modify the `yarn flow` command to
copy the generated `.flowconfig` file into the root directory. The
editor integration will pick this up and show Flow information for
whatever was the last renderer you checked.
Everything else about the setup is the same, and all the renderers will
continue to be checked by CI.
* Failing test for #18657
* Remove incorrect priority check
I think this was just poor factoring on my part in #18411. Honestly it
doesn't make much sense to me, but my best guess is that I must have
thought that when `baseTime > currentChildExpirationTime`, the function
would fall through to the
`currentChildExpirationTime < renderExpirationTime` branch below.
Really I think just made an oopsie.
Regardless, this logic is galaxy brainéd. A goal of the Lanes refactor
I'm working on is to make these types of checks -- is there remaining
work in this tree? -- a lot easier to think about. Hopefully.
* Move renderer `act` to work loop
* Delete `flushSuspenseFallbacksInTests`
This was meant to be a temporary hack to unblock the `act` work, but it
quickly spread throughout our tests.
What it's meant to do is force fallbacks to flush inside `act` even in
Concurrent Mode. It does this by wrapping the `setTimeout` call in a
check to see if it's in an `act` context. If so, it skips the delay and
immediately commits the fallback.
Really this is only meant for our internal React tests that need to
incrementally render. Nobody outside our team (and Relay) needs to do
that, yet. Even if/when we do support that, it may or may not be with
the same `flushAndYield` pattern we use internally.
However, even for our internal purposes, the behavior isn't right
because a really common reason we flush work incrementally is to make
assertions on the "suspended" state, before the fallback has committed.
There's no way to do that from inside `act` with the behavior of this
flag, because it causes the fallback to immediately commit. This has led
us to *not* use `act` in a lot of our tests, or to write code that
doesn't match what would actually happen in a real environment.
What we really want is for the fallbacks to be flushed at the *end` of
the `act` scope. Not within it.
This only affects the noop and test renderer versions of `act`, which
are implemented inside the reconciler. Whereas `ReactTestUtils.act` is
implemented in "userspace" for backwards compatibility. This is fine
because we didn't have any DOM Suspense tests that relied on this flag;
they all use test renderer or noop.
In the future, we'll probably want to move always use the reconciler
implementation of `act`. It will not affect the prod bundle, because we
currently only plan to support `act` in dev. Though we still haven't
completely figured that out. However, regardless of whether we support a
production `act` for users, we'll still need to write internal React
tests in production mode. For that use case, we'll likely add our own
internal version of `act` that assumes a mock Scheduler and might rely
on hacks that don't 100% align up with the public one.
I made a mistake when setting these up a while ago. Setting the NODE_ENV
in the CircleCI config doesn't work because it's also set in the node
script command.
The number of test commands is getting out of control. Might need to fix
it at some point. Not today for me.
* Migrate conditional tests to gate pragma
I searched through the codebase for this pattern:
```js
describe('test suite', () => {
if (!__EXPERIMENTAL__) { // or some other condition
test("empty test so Jest doesn't complain", () => {});
return;
}
// Unless we're in experimental mode, none of the tests in this block
// will run.
})
```
and converted them to the `@gate` pragma instead.
The reason this pattern isn't preferred is because you end up disabling
more tests than you need to.
* Add flag for www release channels
Using a heuristic where I check a flag that is known to only be enabled
in www. I left a TODO to instead set the release channel explicitly in
each test config.
* Add pragma for feature testing: @gate
The `@gate` pragma declares under which conditions a test is expected to
pass.
If the gate condition passes, then the test runs normally (same as if
there were no pragma).
If the conditional fails, then the test runs and is *expected to fail*.
An alternative to `it.experimental` and similar proposals.
Examples
--------
Basic:
```js
// @gate enableBlocksAPI
test('passes only if Blocks API is available', () => {/*...*/})
```
Negation:
```js
// @gate !disableLegacyContext
test('depends on a deprecated feature', () => {/*...*/})
```
Multiple flags:
```js
// @gate enableNewReconciler
// @gate experimental
test('needs both useEvent and Blocks', () => {/*...*/})
```
Logical operators (yes, I'm sorry):
```js
// @gate experimental && (enableNewReconciler || disableSchedulerTimeoutBasedOnReactExpirationTime)
test('concurrent mode, doesn\'t work in old fork unless Scheduler timeout flag is disabled', () => {/*...*/})
```
Strings, and comparion operators
No use case yet but I figure eventually we'd use this to gate on
different release channels:
```js
// @gate channel === "experimental" || channel === "modern"
test('works in OSS experimental or www modern', () => {/*...*/})
```
How does it work?
I'm guessing those last two examples might be controversial. Supporting
those cases did require implementing a mini-parser.
The output of the transform is very straightforward, though.
Input:
```js
// @gate a && (b || c)
test('some test', () => {/*...*/})
```
Output:
```js
_test_gate(ctx => ctx.a && (ctx.b || ctx.c, 'some test'), () => {/*...*/});
```
It also works with `it`, `it.only`, and `fit`. It leaves `it.skip` and
`xit` alone because those tests are disabled anyway.
`_test_gate` is a global method that I set up in our Jest config. It
works about the same as the existing `it.experimental` helper.
The context (`ctx`) argument is whatever we want it to be. I set it up
so that it throws if you try to access a flag that doesn't exist. I also
added some shortcuts for common gating conditions, like `old`
and `new`:
```js
// @gate experimental
test('experimental feature', () => {/*...*/})
// @gate new
test('only passes in new reconciler', () => {/*...*/})
```
Why implement this as a pragma instead of a runtime API?
- Doesn't require monkey patching built-in Jest methods. Instead it
compiles to a runtime function that composes Jest's API.
- Will be easy to upgrade if Jest ever overhauls their API or we switch
to a different testing framework (unlikely but who knows).
- It feels lightweight so hopefully people won't feel gross using it.
For example, adding or removing a gate pragma will never affect the
indentation of the test, unlike if you wrapped the test in a
conditional block.
* Compatibility with console error/warning tracking
We patch console.error and console.warning to track unexpected calls
in our tests. If there's an unexpected call, we usually throw inside
an `afterEach` hook. However, that's too late for tests that we
expect to fail, because our `_test_gate` runtime can't capture the
error. So I also check for unexpected calls inside `_test_gate`.
* Move test flags to dedicated file
Added some instructions for how the flags are set up and how to
use them.
* Add dynamic version of gate API
Receives same flags as the pragma.
If we ever decide to revert the pragma, we can codemod them to use
this instead.
* Add more edge cases to fixture
Also adjust some expectations. I think the column should ideally be 1 but varies.
The Example row is one line off because it throws on the hook but should ideally be the component.
Similarly class components with constructors may have the line in the constructor.
* Account for the construct call taking a stack frame
We do this by first searching for the first different frame, then find
the same frames and then find the first different frame again.
* Throw controls
Otherwise they don't get a stack frame associated with them in IE.
* Protect against generating stacks failing
Errors while generating stacks will bubble to the root. Since this technique
is a bit sketchy, we should probably protect against it.
* Don't construct the thing that throws
Instead, we pass the prototype as the "this". It's new every time anyway.
* Implement component stack extraction hack
* Normalize errors in tests
This drops the requirement to include owner to pass the test.
* Special case tests
* Add destructuring to force toObject which throws before the side-effects
This ensures that we don't double call yieldValue or advanceTime in tests.
Ideally we could use empty destructuring but ES lint doesn't like it.
* Cache the result in DEV
In DEV it's somewhat likely that we'll see many logs that add component
stacks. This could be slow so we cache the results of previous components.
* Fixture
* Add Reflect to lint
* Log if out of range.
* Fix special case when the function call throws in V8
In V8 we need to ignore the first line. Normally we would never get there
because the stacks would differ before that, but the stacks are the same if
we end up throwing at the same place as the control.
Modules that belong to one fork should not import modules that belong to
the other fork.
Helps make sure you correctly update imports when syncing changes across
implementations.
Also could help protect against code size regressions that might happen
if one of the forks accidentally depends on two copies of the same
module.
* Remove unnecessary workInProgress line
* Mutate workInProgress instead of returning
We were ambivalent about this before.
* Make handleError a void method too
We currently use the expiration time to represent the timeout of a
transition. Since we intend to stop treating work priority as a
timeline, we can no longer use this trick.
In this commit, I've changed it to store the event time on the update
object instead. Long term, we will store event time on the root as a map
of transition -> event time. I'm only storing it on the update object
as a temporary workaround to unblock the rest of the changes.
We can't patch the row. We could give these their own "built-in" stack
frame since they're conceptually HoCs. However, from a debugging
perspective this is not very useful meta data and quite noisy. So I'm
just going to exclude them.
Adds command `yarn merge-fork`.
```sh
yarn merge-fork --base-dir=packages/react-reconciler/src ReactFiberWorkLoop
```
This will take all the changes in `ReactFiberWorkLoop.new.js` and apply
them to `ReactFiberWorkLoop.old.js`.
You can merge multiple modules at a time:
```sh
yarn merge-fork \
--base-dir=packages/react-reconciler/src \
ReactFiberWorkLoop \
ReactFiberBeginWork \
ReactFiberCompleteWork \
ReactFiberCommitWork
```
You can provide explicit "old" and "new" file names. This only works
for one module at a time:
```sh
yarn merge-fork \
--base-dir=packages/react-reconciler/src \
--old=ReactFiberExpirationTime.js \
--new=ReactFiberLane.js
```
The default is to merge changes from the new module to the old one. To
merge changes in the opposite direction, use `--reverse`.
```sh
yarn merge-fork \
--reverse \
--base-dir=packages/react-reconciler/src \
ReactFiberWorkLoop
```
By default, the changes are compared to HEAD. You can use `--base-ref`
to compare to any rev. For example, while working on a PR, you might
make multiple commits to the new fork before you're ready to backport
them to the old one. In that case, you want to compare to the merge
base of your PR branch:
```sh
yarn merge-fork \
--base-ref=$(git merge-base HEAD origin/master)
--base-dir=packages/react-reconciler/src \
ReactFiberWorkLoop
```
All changes in this commit were generated by the following commands.
Copy each module that ends with `.old` to a new file that ends
with `.new`:
```sh
for f in packages/react-reconciler/src/*.old.js; do cp "$f" "$(echo "$f" | sed s/\.old/\.new/)"; done
```
Then transform the internal imports:
```sh
grep -rl --include="*.new.js" '.old' packages/react-reconciler/src/| xargs sed -i '' "s/\.old\'/\.new\'/g"
```
Some of our internal reconciler types have leaked into other packages.
Usually, these types are treated as opaque; we don't read and write
to its fields. This is good.
However, the type is often passed back to a reconciler method. For
example, React DOM creates a FiberRoot with `createContainer`, then
passes that root to `updateContainer`. It doesn't do anything with the
root except pass it through, but because `updateContainer` expects a
full FiberRoot, React DOM is still coupled to all its fields.
I don't know if there's an idiomatic way to handle this in Flow. Opaque
types are simlar, but those only work within a single file. AFAIK,
there's no way to use a package as the boundary for opaqueness.
The immediate problem this presents is that the reconciler refactor will
involve changes to our internal data structures. I don't want to have to
fork every single package that happens to pass through a Fiber or
FiberRoot, or access any one of its fields. So my current plan is to
share the same Flow type across both forks. The shared type will be a
superset of each implementation's type, e.g. Fiber will have both an
`expirationTime` field and a `lanes` field. The implementations will
diverge, but not the types.
To do this, I lifted the type definitions into a separate module.
* Drop the .internal.js suffix on some files that don't need it anymore
* Port some ops patterns to scheduler yield
* Fix triangle test to avoid side-effects in constructor
* Move replaying of setState updaters until after the effect
Otherwise any warnings get silenced if they're deduped.
* Drop .internal.js in more files
* Don't check propTypes on a simple memo component unless it's lazy
Comparing the elementType doesn't work for this because it will never be
the same for a simple element.
This caused us to double validate these. This was covered up because in
internal tests this was deduped since they shared the prop types cache
but since we now inline it, it doesn't get deduped.
* Don't use closures in DevTools injection
Nested closures are tricky. They're not super efficient and when they share
scope between multiple closures they're hard for a compiler to optimize.
It's also unclear how many versions will be created.
By hoisting things out an just make it simple calls the compiler can do
a much better job.
* Store injected hook to work around fast refresh
* Disable console log during the second rerender
* Use the disabled log to avoid double yielding values in scheduler mock
* Reenable debugRenderPhaseSideEffectsForStrictMode in tests that can
* Add failing tests for lazy components
* Fix bailout broken in lazy components due to default props resolving
We should never compare unresolved props with resolved props. Since comparing
resolved props by reference doesn't make sense, we use unresolved props in that
case. Otherwise, resolved props are used.
* Avoid reassigning props warning when we bailout
* Bugfix: Render phase update leads to dropped work
Render phase updates should not affect the `fiber.expirationTime` field.
We don't have to set anything on the fiber because we're going to
process the render phase update immediately.
We also shouldn't reset the `expirationTime` field in between render
passes because it represents the remaining work left in the update
queues. During the re-render, the updates that were skipped in the
original pass are not processed again.
I think my original motivation for using this field for render phase
updates was so I didn't have to add another module level variable.
* Add repro case for #18486
Co-authored-by: Dan Abramov <dan.abramov@me.com>
* Add another test for #18515 using pings
Adds a regression test for the same underlying bug as #18515 but using
pings.
Test already passes, but I confirmed it fails if you revert the fix
in #18515.
* Set nextPendingLevel after commit, too
* Reproduce a bug where `flushDiscreteUpdates` causes fallback never to be committed
* Ping suspended level when canceling its timer
Make sure the suspended level is marked as pinged so that we return back
to it later, in case the render we're about to start gets aborted.
Generally we only reach this path via a ping, but we shouldn't assume
that will always be the case.
* Clear finished discrete updates during commit phase
If a root is finished at a priority lower than that of the latest pending discrete
updates on it, these updates must have been finished so we can clear them now.
Otherwise, a later call of `flushDiscreteUpdates` would start a new empty render
pass which may cause a scheduled timeout to be cancelled.
* Add TODO
Happened to find this while writing a test. A JSX element comparison
failed because one of them elements had a functional component as an
owner, which should ever happen.
I'll add a regression test later.
Co-authored-by: Andrew Clark <git@andrewclark.io>
* Filter certain DOM attributes (e.g. src, href) if their values are empty strings
This prevents e.g. <img src=""> from making an unnecessar HTTP request for certain browsers.
* Expanded warning recommendation
* Improved error message
* Further refined error message
* Add useOpaqueIdentifier Hook
We currently use unique IDs in a lot of places. Examples are:
* `<label for="ID">`
* `aria-labelledby`
This can cause some issues:
1. If we server side render and then hydrate, this could cause an
hydration ID mismatch
2. If we server side render one part of the page and client side
render another part of the page, the ID for one part could be
different than the ID for another part even though they are
supposed to be the same
3. If we conditionally render something with an ID , this might also
cause an ID mismatch because the ID will be different on other
parts of the page
This PR creates a new hook `useUniqueId` that generates a different
unique ID based on whether the hook was called on the server or client.
If the hook is called during hydration, it generates an opaque object
that will rerender the hook so that the IDs match.
Co-authored-by: Andrew Clark <git@andrewclark.io>
* Add feature flag
* Split stack from current fiber
You can get stack from any fiber, not just current.
* Refactor description of component frames
These should use fiber tags for switching. This also puts the relevant code
behind DEV flags.
* We no longer expose StrictMode in component stacks
They're not super useful and will go away later anyway.
* Update tests
Context is no longer part of SSR stacks. This was already the case on the
client.
forwardRef no longer is wrapped on the stack. It's still in getComponentName
but it's probably just noise in stacks. Eventually we'll remove the wrapper
so it'll go away anyway. If we use native stack frames they won't have this
extra wrapper.
It also doesn't pick up displayName from the outer wrapper. We could maybe
transfer it but this will also be fixed by removing the wrapper.
* Forward displayName onto the inner function for forwardRef and memo in DEV
This allows them to show up in stack traces.
I'm not doing this for lazy because lazy is supposed to be called on the
consuming side so you shouldn't assign it a name on that end. Especially
not one that mutates the inner.
* Use multiple instances of the fake component
We mutate the inner component for its name so we need multiple copies.
* Remove unnecessary CapturedError fields.
componentName is not necessary and is misleading when the error is caused
elsewhere in the stack. The stack is sufficient.
The many error boundary fields are unnecessary because they can be inferred
by the boundary itself.
* Don't attempt to build a stack twice
If it was possible, it would've been done in createCapturedValue.
* Push the work needed by the works into the forks
This avoids needing this in the npm published case.
* Lazily initialize models as they're read intead of eagerly when received
This ensures that we don't spend CPU cycles processing models that we're
not going to end up rendering.
This model will also allow us to suspend during this initialization if
data is not yet available to satisfy the model.
* Refactoring carefully to ensure bundles still compile to something optimal
* Remove generic from Response
The root model needs to be cast at one point or another same as othe
chunks. So we can parameterize the read instead of the whole Response.
* Read roots from the 0 key of the map
The special case to read the root isn't worth the field and code.
* Store response on each Chunk
Instead of storing it on the data tuple which is kind of dynamic, we store
it on each Chunk. This uses more memory. Especially compared to just making
initializeBlock a closure, but overall is simpler.
* Rename private fields to underscores
Response objects are exposed.
* Encode server components as delayed references
This allows us to stream in server components one after another over the
wire. It also allows parallelizing their fetches and resuming only the
server component instead of the whole parent block.
This doesn't yet allow us to suspend deeper while waiting on this content
because we don't have "lazy elements".
* Eject CRA from Flight
We need to eject because we're going to add a custom Webpack Plugin.
We can undo this once the plugin has upstreamed into CRA.
* Add Webpack plugin build
I call this entry point "webpack-plugin" instead of "plugin" even though
this is a webpack specific package. That's because there will also be a
Node.js plugin to do the server transform.
* Add Flight Webpack plugin to fixture
* Rm UMD builds
* Transform classes
* Rename webpack-plugin to plugin
This avoids the double webpack name. We're going to reuse this for both
server and client.
* Remove /dist/ UMD builds
We publish UMDs to npm (and we're considering stopping even that).
This means we'll stop publishing to http://react.zpao.com/builds/master/latest/
* Update fixture paths
This is a variant of the fix in 5a0f1d. We can't rely on the primary
fiber's `childExpirationTime` field to be correct.
In this case, we can read from the Suspense boundary fiber instead.
This will include updates that exist in the fallback fiber, but that's
not a big deal; the important thing is that we don't drop updates.
* Enable prefer-const rule
Stylistically I don't like this but Closure Compiler takes advantage of
this information.
* Auto-fix lints
* Manually fix the remaining callsites
* Upgrade Closure
There are newer versions but they don't yet have corresponding releases
of google-closure-compiler-osx.
* Configure build
* Refactor ReactSymbols a bit
Provides a little better output.
`onInput` behaves the same as `onChange` for controlled inputs as far as I
know, so React should not print the following warning when `onInput` is
present.
> Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
* add email input fixture to show cursor jump
* fix cursor jump in email input
Co-authored-by: Peter Potapov <dr.potapoff-peter@yandex.ru>
* add regression tests to ensure attributes are working
Co-authored-by: Peter Potapov <dr.potapoff-peter@yandex.ru>
* test(SuspenseList): Add failing test for class component
* Reset stateNode when resetWorkInProgress
This is supposed to put the Fiber into the same state as if it was just
created by child fiber reconciliation. For newly created fibers, that means
that stateNode is null.
Co-authored-by: Sebastian Silbermann <silbermann.sebastian@gmail.com>
* Enable new passive effect behavior for FB builds
Previously this behavior was controlled by GKs. This PR updates the flags to be enabled statically. It also enables the flags in the test builds.
* Revert "ReactDOM.useEvent: enable on internal www and add inspection test (#18395)"
This reverts commit e0ab1a429d.
* Revert "ReactDOM.useEvent: Add support for experimental scopes API (#18375)"
This reverts commit a16b349745.
* ReactDOM.useEvent: Add support for experimental scopes API
* Refactor: visit CallExpression
Instead of visiting the functions and looking up to see if they're in a Hook call, visit Hook calls and look down to see if there's a callback inside. I will need this refactor so I can visit functions declared outside the call.
* Check deps when callback body is outside the Hook call
* Handle the unknown case
* Bugfix: Suspended update must finish to unhide
When we commit a fallback, we cannot unhide the content without including
the level that originally suspended. That's because the work at level
outside the boundary (i.e. everything that wasn't hidden during that
render) already committed.
* Test unblocking with a high-pri update
We store an effect pointer so we can backtrack in the effect list in some
cases. This is a stateful variable. If we interrupt a render we need to
reset it.
This field was added after the optimization was added and I didn't remember
to reset it here.
Otherwise we end up not resetting the firstEffect so it points to a stale
list. As a result children don't end up inserted like we think they were.
Then we try to remove them it errors.
It would be nicer to just get rid of the effect list and use the tree for
effects instead. Maybe we still need something for deletions tho.
React can't directly detect a memory leak, but there are some clues that warn about one. One of these clues is when an unmounted React component tries to update its state. For example, if a component forgets to remove an event listener when unmounting, that listener may be called later and try to update state, at which point React would warn about the potential leak.
Warning signals like this are more useful if they're strong. For this reason, it's good to always avoid updating state from inside of an effect's cleanup function. Even when you know there is no potential leak, React has no way to know and so it will warn anyway.
In most cases we suggest moving state updates to the useEffect() body instead (to avoid triggering the warning). This works so long as the component is updating its own state (or the state of a descendant). However this will not work when a component updates its parent state in a cleanup function. If such a component is unmounted but its parent remains mounted, the state will be incorrect. For this reason, we now avoid showing the warning if a component is updating an ancestor.
This assignment should have been deleted in #18384. It was deleted in
the other branches, but I missed this one. About to open a PR that
includes a test that covers this branch.
* Minor test refactor: `resolveText`
Adds a `resolveText` method as an alternative to using timers. Also
removes dependency on react-cache (for just this one test file; can do
the others later).
Timer option is still there if you provide a `ms` prop.
* Bugfix: Dropped updates in suspended tree
When there are multiple updates at different priority levels inside
a suspended subtree, all but the highest priority one is dropped after
the highest one suspends.
We do have tests that cover this for updates that originate outside of
the Suspense boundary, but not for updates that originate inside.
I'm surprised it's taken us this long to find this issue, but it makes
sense in that transition updates usually originate outside the boundary
or "seam" of the part of the UI that is transitioning.
* Bugfix: Suspense fragment skipped by setState
Fixes a bug where updates inside a suspended tree are dropped because
the fragment fiber we insert to wrap the hidden children is not part of
the return path, so it doesn't get marked during setState.
As a workaround, I recompute `childExpirationTime` right before deciding
to bail out by bubbling it up from the next level of children.
This is something we should consider addressing when we refactor the
Fiber data structure.
* Add back `lastPendingTime` field
This reverts commit 9a541139dfe36e8b9b02b1c6585889e2abf97389.
I want to use this so we can check if there might be any lower priority
updates in a suspended tree.
We can remove it again during the expiration times refactor.
* Use `lastPendingTime` instead of Idle
We don't currently have an mechanism to check if there are lower
priority updates in a subtree, but we can check if there are any in the
whole root. This still isn't perfect but it's better than using Idle,
which frequently leads to redundant re-renders.
When we refactor `expirationTime` to be a bitmask, this will no longer
be necessary because we'll know exactly which "task bits" remain.
* Add a test for updating the fallback
This is equivalent to the jsx-runtime in that this is what the compiled
output on the server is supposed to target.
It's really just the same code for all the different Flights, but they
have different types in their arguments so each one gets their own entry
point. We might use this to add runtime warnings per entry point.
Unlike the client-side React.block call this doesn't provide the factory
function that curries the load function. The compiler is expected to wrap
this call in the currying factory.
* Formalize the Wakeable and Thenable types
We use two subsets of Promises throughout React APIs. This introduces
the smallest subset - Wakeable. It's the thing that you can throw to
suspend. It's something that can ping.
I also use a shared type for Thenable in the cases where we expect a value
so we can be a bit more rigid with our us of them.
* Make Chunks into Wakeables instead of using native Promises
This value is just going from here to React so we can keep it a lighter
abstraction throughout.
* Renamed thenable to wakeable in variable names
Originally the idea was to hide all suspending behind getters or proxies.
However, this has some issues with perf on hot code like React elements.
It also makes it too easy to accidentally access it the first time in an
effect or callback where things aren't allowed to suspend. Making it
an explicit method call avoids this issue.
All other suspending has moved to explicit lazy blocks (and soon elements).
The only thing remaining is the root. We could require the root to be an
element or block but that creates an unfortunate indirection unnecessarily.
Instead, I expose a readRoot method on the response. Typically we try to
avoid virtual dispatch but in this case, it's meant that you build
abstractions on top of a Flight response so passing it a round is useful.
DevTools previously used the NPM events package for dispatching events. This package has an unfortunate flaw though- if a listener throws during event dispatch, no subsequent listeners are called. I've replaced that event dispatcher with my own implementation that ensures all listeners are called before it re-throws an error.
This commit replaces that event emitter with a custom implementation that calls all listeners before re-throwing an error.
* Regression test for map() returning an array
* Add forgotten argument
This fixes the bug.
* Remove unused arg and retval
These aren't directly observable. The arg wasn't used, it's accidental and I forgot to remove. The retval was triggering a codepath that was unnecessary (pushing to array) so I removed that too.
* Flowify ReactChildren
* Tighten up types
* Rename getComponentKey to getElementKey
This reverts commit cf0081263c.
The changes to the test code relate to changes in JSDOM that come with Jest 25:
* Several JSDOM workarounds are no longer needed.
* Several tests made assertions to match incorrect JSDOM behavior (e.g. setAttribute calls) that JSDOM has now patched to match browsers.
* https://codesandbox.io/s/resets-value-of-datetime-input-to-fix-bugs-in-ios-safari-1ppwh
* JSDOM no longer triggers default actions when dispatching click events.
* https://codesandbox.io/s/beautiful-cdn-ugn8f
* JSDOM fixed (jsdom/jsdom#2700) a bug so that calling focus() on an already focused element does not dispatch a FocusEvent.
* JSDOM now supports passive events.
* JSDOM has improved support for custom CSS properties.
* But requires jsdom/cssstyle#112 to land to support webkit prefixed properties.
* Resolve Server-side Blocks instead of Components
React elements should no longer be used to extract arbitrary data but only
for prerendering trees.
Blocks are used to create asynchronous behavior.
* Resolve Blocks in the Client
* Tests
* Bug fix relay JSON traversal
It's supposed to pass the original object and not the new one.
* Lint
* Move Noop Module Test Helpers to top level entry points
This module has shared state. It needs to be external from builds.
This lets us test the built versions of the Noop renderer.
* Don't pool traversal context
* Remove traverseAllChildrenImpl indirection
All usages are internal so we can simply use the inner function directly.
* Implement forEach through map
* Remove second usage of traverseAllChildren
This isn't useful by itself but makes the layering easier to follow. traverseAllChildren is only used at the lowest layer now.
* Reimplement count() and toArray() in terms of map()
* Inline the only use of mapSingleChildIntoContext
* Move forEach down in the file
* Use the language
Get rid of the traversal context. Use closures.
* Make mapIntoArray take an already escaped prefix
* Move count state out of mapIntoArray
* Inline traverseAllChildren into mapIntoArray
* Inline handleChild into mapIntoArray
* Refactor Lazy Components
* Switch Blocks to using a Lazy component wrapper
Then resolve to a true Block inside.
* Test component names of lazy Blocks
This is a really old one and all callers have since been codemodded away
anyway because of problems.
This file is not really as rigorously maintained as the official Flow types
but has a few more specifics. However, the inconsistency causes problems
when you try to pass files typed using the built-in Flow typing for React
and mix it with these.
We just happen to get away with it because we compile out the types. If we
didn't we would hit those problems by even using these in our renderers.
* Rename lower case isomorphic default exports modules to upper case named exports
We're somewhat inconsistent here between e.g. ReactLazy and memo.
Let's pick one.
This also moves the responder, fundamental, scope creators from shared
since they're isomorphic and same as the other creators.
* Move some files that are specific to the react-reconciler from shared
Individual renderers are allowed to deep require into the reconciler.
* Move files specific to react-dom from shared
react-interactions is right now dom specific (it wasn't before) so we can
type check it together with other dom stuff. Avoids the need for
a shared ReactDOMTypes to be checked by RN for example.
* Move ReactWorkTags to the reconciler
* Move createPortal to export from reconciler
Otherwise Noop can't access it since it's not allowed deep requires.
I accidentally did that thing again where I updated a PR branch to
be the same as the tip of master, which confused GitHub and caused it
to run PR checks against master.
Follow ups from https://github.com/facebook/react/pull/18334
I also introduced the concept of a module reference on the client too.
We don't need this for webpack so that gets compiled out but we need it
for www. Similarly I also need a difference between preload and load.
Error codes don't need to be pulled from CI anymore because the ones
in source are already expected to match the build output.
I noticed this when running the 16.13.1 release. Patch releases are cut
with the commit used to build the previous release as a base. So the
publish script accidentally reverted the changes that had landed to
the error codes file since then.
The publish script was written before we switched to running patch
releases out-of-band, so when updating the local package.json version
numbers, it accidentally reverted other changes that have landed to
master since 16.13 was released.
Per discussion at Facebook, we think hooks have reached a tipping point where it is more valuable to lint against potential hooks in classes than to worry about false positives.
Test plan:
```
# run from repo root
yarn test --watch RuleOfHooks
```
* [DevTools] Add shortcut keys for tab switching
* Use LocalStorage to remember most recently selected tab
Resolves#18227 and #18226
Co-authored-by: Brian Vaughn <brian.david.vaughn@gmail.com>
There was an inconsistency present on line 99 regarding the punctuation of the comment, all other comments found end in a period and this line had it's period omitted.
* Move unsubscribe fork to EventListener
That way we can statically compile out more of these indirections.
* Don't use the EventListener fork for Modern WWW builds
* Change the warning to not say "function body"
This warning is more generic and may happen with class components too.
* Dedupe by the rendering component
* Don't warn outside of render
This PR adds the jsx-runtime and jsx-dev-runtime modules for the JSX Babel Plugin. WWW still relies on jsx/jsxs/jsxDEV from the "react" module, so once we refactor the code to point to the runtime modules we will remove jsx/jsxs/jsxDEV from the "react" module.
* improve error message for cross-functional component updates
* correctly use %s by quoting it
* use workInProgress and lint
* add test assertion
* fix test
* Improve the error message
Co-authored-by: Dan Abramov <dan.abramov@me.com>
Don't warn about unmounted state updates from within passive destroy function
* Fixed test conditional. (It broke after recent variant refactor.)
* Changed warning wording for setState from within useEffect destroy callback
* ReactFiberReconciler -> ReactFiberReconciler.old
* Set up infra for react-reconciler fork
We're planning to land some significant refactors of the reconciler.
We want to be able to gradually roll out the new implementation side-by-
side with the existing one. So we'll create a short lived fork of the
react-reconciler package. Once the new implementation has stabilized,
we'll delete the old implementation and promote the new one.
This means, for as long as the fork exists, we'll need to maintain two
separate implementations. This sounds painful, but since the forks will
still be largely the same, most changes will not require two separate
implementations. In practice, you'll implement the change in the old
fork and then copy paste it to the new one.
This commit only sets up the build and testing infrastructure. It does
not actually fork any modules. I'll do that in subsequent PRs.
The forked version of the reconciler will be used to build a special
version of React DOM. I've called this build ReactDOMForked. It's only
built for www; there's no open source version.
The new reconciler is disabled by default. It's enabled in the
`yarn test-www-variant` command. The reconciler fork isn't really
related to the "variant" feature of the www builds, but I'm piggy
backing on that concept to avoid having to add yet another
testing dimension.
For the browser extension, these views get rendered into portals and so they don't inherit the box-sizing style from the .DevTools wrapper element. This causes views like the Profiler commit selector to subtly break.
useMutableSource hook
useMutableSource() enables React components to safely and efficiently read from a mutable external source in Concurrent Mode. The API will detect mutations that occur during a render to avoid tearing and it will automatically schedule updates when the source is mutated.
RFC: reactjs/rfcs#147
* Bugfix: "Captured" updates on legacy queue
This fixes a bug with error boundaries. Error boundaries have a notion
of "captured" updates that represent errors that are thrown in its
subtree during the render phase. These updates are meant to be dropped
if the render is aborted.
The bug happens when there's a concurrent update (an update from an
interleaved event) in between when the error is thrown and when the
error boundary does its second pass. The concurrent update is
transferred from the pending queue onto the base queue. Usually, at this
point the base queue is the same as the current queue. So when we
append the pending updates to the work-in-progress queue, it also
appends to the current queue.
However, in the case of an error boundary's second pass, the base queue
has already forked from the current queue; it includes both the
"captured" updates and any concurrent updates. In that case, what we
need to do is append separately to both queues. Which we weren't doing.
That isn't the full story, though. You would expect that this mistake
would manifest as dropping the interleaved updates. But instead what
was happening is that the "captured" updates, the ones that are meant
to be dropped if the render is aborted, were being added to the
current queue.
The reason is that the `baseQueue` structure is a circular linked list.
The motivation for this was to save memory; instead of separate `first`
and `last` pointers, you only need to point to `last`.
But this approach does not work with structural sharing. So what was
happening is that the captured updates were accidentally being added
to the current queue because of the circular link.
To fix this, I changed the `baseQueue` from a circular linked list to a
singly-linked list so that we can take advantage of structural sharing.
The "pending" queue, however, remains a circular list because it doesn't
need to be persistent.
This bug also affects the root fiber, which uses the same update queue
implementation and also acts like an error boundary.
It does not affect the hook update queue because they do not have any
notion of "captured" updates. So I've left it alone for now. However,
when we implement resuming, we will have to account for the same issue.
* Ensure base queue is a clone
When an error boundary captures an error, we append the error update
to the work-in-progress queue only so that if the render is aborted,
the error update is dropped.
Before appending to the queue, we need to make sure the queue is a
work-in-progress copy. Usually we clone the queue during
`processUpdateQueue`; however, if the base queue has lower priority
than the current render, we may have bailed out on the boundary fiber
without ever entering `processUpdateQueue`. So we need to lazily clone
the queue.
* Add warning to protect against refactor hazard
The hook queue does not have resuming or "captured" updates, but if
we ever add them in the future, we'll need to make sure we check if the
queue is forked before transfering the pending updates to them.
This replaces the HTML renderer with instead resolving host elements into
arrays tagged with the react.element symbol. These turn into proper
React Elements on the client.
The symbol is encoded as the magical value "$". This has security implications
so this special value needs to remain escaped for other strings.
We could just encode the element as {$$typeof: "$", key: key props: props}
but that's a lot more bytes. So instead I encode it as:
["$", key, props] and then convert it back.
It would be nicer if React's reconciler could just accept these tuples.
* Add ReactFlightServerConfig intermediate
This just forwards to the stream version of Flight which is itself forked
between Node and W3C streams.
The dom-relay goes directly to the Relay config though which allows it to
avoid the stream part of Flight.
* Separate streaming protocol into the Stream config
* Split streaming parts into the ReactFlightServerConfigStream
This decouples it so that the Relay implementation doesn't have to encode
the JSON to strings. Instead it can be fed the values as JSON objects and
do its own encoding.
* Split FlightClient into a basic part and a stream part
Same split as the server.
* Expose lower level async hooks to Relay
This requires an external helper file that we'll wire up internally.
* Rename to clarify that it's client-only
* Rename FizzStreamer to FizzServer for consistency
* Rename react-flight to react-client/flight
For consistency with react-server. Currently this just includes flight
but it could be expanded to include the whole reconciler.
* Add Relay Flight Build
* Rename ReactServerHostConfig to ReactServerStreamConfig
This will be the config specifically for streaming purposes.
There will be other configs for other purposes.
* Require deep for reconcilers
* Delete inline* files
* Delete react-reconciler/persistent
This no longer makes any sense because it react-reconciler takes
supportsMutation or supportsPersistence as options. It's no longer based
on feature flags.
* Fix jest mocking
* Fix Flow strategy
We now explicitly list which paths we want to be checked by a renderer.
For every other renderer config we ignore those paths.
Nothing is "any" typed. So if some transitive dependency isn't reachable
it won't be accidentally "any" that leaks.
* Lazify Blocks
Blocks now initialize lazily.
* Initialize Blocks eagerly in ChildFiber
This is for the case when it's a new Block that hasn't yet initialized.
We need to first initialize it to see what "render function" it resolves
to so that we can use that in our comparison.
* Remove extra import type line
* Failing: Dropped effects in Legacy Mode Suspense
* Transfer mounted effects on suspend in legacy mode
In legacy mode, a component that suspends bails out and commit in
its previous state. If the component previously had mounted effects,
we must transfer those to the work-in-progress so they don't
get dropped.
In CI, we run our test suite against multiple build configurations. For
example, we run our tests in both dev and prod, and in both the
experimental and stable release channels. This is to prevent accidental
deviations in behavior between the different builds. If there's an
intentional deviation in behavior, the test author must account
for them.
However, we currently don't run tests against the www builds. That's
a problem, because it's common for features to land in www before they
land anywhere else, including the experimental release channel.
Typically we do this so we can gradually roll out the feature behind
a flag before deciding to enable it.
The way we test those features today is by mutating the
`shared/ReactFeatureFlags` module. There are a few downsides to this
approach, though. The flag is only overridden for the specific tests or
test suites where you apply the override. But usually what you want is
to run *all* tests with the flag enabled, to protect against unexpected
regressions.
Also, mutating the feature flags module only works when running the
tests against source, not against the final build artifacts, because the
ReactFeatureFlags module is inlined by the build script.
Instead, we should run the test suite against the www configuration,
just like we do for prod, experimental, and so on. I've added a new
command, `yarn test-www`. It automatically runs in CI.
Some of the www feature flags are dynamic; that is, they depend on
a runtime condition (i.e. a GK). These flags are imported from an
external module that lives in www. Those flags will be enabled for some
clients and disabled for others, so we should run the tests against
*both* modes.
So I've added a new global `__VARIANT__`, and a new test command `yarn
test-www-variant`. `__VARIANT__` is set to false by default; when
running `test-www-variant`, it's set to true.
If we were going for *really* comprehensive coverage, we would run the
tests against every possible configuration of feature flags: 2 ^
numberOfFlags total combinations. That's not practical, though, so
instead we only run against two combinations: once with `__VARIANT__`
set to `true`, and once with it set to `false`. We generally assume that
flags can be toggled independently, so in practice this should
be enough.
You can also refer to `__VARIANT__` in tests to detect which mode you're
running in. Or, you can import `shared/ReactFeatureFlags` and read the
specific flag you can about. However, we should stop mutating that
module going forward. Treat it as read-only.
In this commit, I have only setup the www tests to run against source.
I'll leave running against build for a follow up.
Many of our tests currently assume they run only in the default
configuration, and break when certain flags are toggled. Rather than fix
these all up front, I've hard-coded the relevant flags to the default
values. We can incrementally migrate those tests later.
* Implemented Profiler onCommit() and onPostCommit() hooks
* Added enableProfilerCommitHooks feature flag for commit hooks
* Moved onCommit and onPassiveCommit behind separate feature flag
* Revert "Revert "feat: honor displayName of context types (#18035)" (#18223)"
This reverts commit 3ee812e6b6.
* Add warning of displayName is set on the consumer
* dedupe warning
* This type is all wrong and nothing cares because it's all any
* Refine Flow types of Lazy Components
We can type each condition.
* Remove _ctor field from Lazy components
This field is not needed because it's only used before we've initialized,
and we don't have anything else to store before we've initialized.
* Check for _ctor in case it's an older isomorphic that created it
We try not to break across minors but it's no guarantee.
* Move types and constants from shared to isomorphic
The "react" package owns the data structure of the Lazy component. It
creates it and decides how any downstream renderer may use it.
* Move constants to shared
Apparently we can't depend on react/src/ because the whole package is
considered "external" as far as rollup is concerned.
* Bugfix: Expiring a partially completed tree (#17926)
* Failing test: Expiring a partially completed tree
We should not throw out a partially completed tree if it expires in the
middle of rendering. We should finish the rest of the tree without
yielding, then finish any remaining expired levels in a single batch.
* Check if there's a partial tree before restarting
If a partial render expires, we should stay in the concurrent path
(performConcurrentWorkOnRoot); we'll stop yielding, but the rest of the
behavior remains the same.
We will only revert to the sync path (performSyncWorkOnRoot) when
starting on a new level.
This approach prevents partially completed concurrent work from
being discarded.
* New test: retry after error during expired render
* Regression: Expired partial tree infinite loops
Adds regression tests that reproduce a scenario where a partially
completed tree expired then fell into an infinite loop.
The code change that exposed this bug made the assumption that if you
call Scheduler's `shouldYield` from inside an expired task, Scheduler
will always return `false`. But in fact, Scheduler sometimes returns
`true` in that scenario, which is a bug.
The reason it worked before is that once a task timed out, React would
always switch to a synchronous work loop without checking `shouldYield`.
My rationale for relying on `shouldYield` was to unify the code paths
between a partially concurrent render (i.e. expires midway through) and
a fully concurrent render, as opposed to a render that was synchronous
the whole time. However, this bug indicates that we need a stronger
guarantee within React for when tasks expire, given that the failure
case is so catastrophic. Instead of relying on the result of a dynamic
method call, we should use control flow to guarantee that the work is
synchronously executed.
(We should also fix the Scheduler bug so that `shouldYield` always
returns false inside an expired task, but I'll address that separately.)
* Always switch to sync work loop when task expires
Refactors the `didTimeout` check so that it always switches to the
synchronous work loop, like it did before the regression.
This breaks the error handling behavior that I added in 5f7361f (an
error during a partially concurrent render should retry once,
synchronously). I'll fix this next. I need to change that behavior,
anyway, to support retries that occur as a result of `flushSync`.
* Retry once after error even for sync renders
Except in legacy mode.
This is to support the `useOpaqueReference` hook, which uses an error
to trigger a retry at lower priority.
* Move partial tree check to performSyncWorkOnRoot
* Factor out render phase
Splits the work loop and its surrounding enter/exit code into their own
functions. Now we can do perform multiple render phase passes within a
single call to performConcurrentWorkOnRoot or performSyncWorkOnRoot.
This lets us get rid of the `didError` field.
* Added missing @flow pragma to React.js
* Fixed useContext() return type definition
* Fixed previously masked Flow errors in DevTools and react-interactions packages
* Added displayName to internal Context Flow type
* Removed Flow generic annotations for createResponder
This seems to cause a parsing error. (Not sure why.) The API is deprecated anyway so I'm being lazy for now and just adding a .
* Only use Rollup's CommonJS plugin for "react-art"
We still need it for the "art" UMD builds but nothing else should have
CommonJS dependencies anymore.
* react-debug-tools and jest-react should leave object-assign as an external dep
This avoids it being compiled into the output.
* Check in a forked version of object-assign
This one uses ES modules so that we can inline it into UMD builds.
We could wait for object-assign to make an ESM export but we're going to
remove this dependency and assume global polyfills in the next version
anyway. However, we'd have to figure out how to keep the copyright header
and it'll get counted in terms of byte size (even if other tooling removes
it).
A lot of headache when we have our own implementation anyway. So I'll just
use that.
Ours is not resilient to checking certain browser bugs but those browsers
are mostly unused anyway. (Even FB breaks on them presumably.)
We also don't need to be resilient to Symbols since the way React uses it
we shouldn't need to copy symbols
* Don't transpile Object.assign to object-assign in object-assign
The polyfill needs to be able to feature detect Object.assign.
* improve findByType error message
* fix flow typing
* Adding a test for the "Unknown" branch when `getComponentName()` returns a falsy value. The error message in this case not the most descriptive but seems consistent with the `getComponentName(type) || 'Unknown'` pattern seen in multiple places in this code base.
* Move remaining things to named exports
The interesting case here is the noop renderers. The wrappers around the
reconciler now changed to use a local export that gets mutated.
ReactNoop and ReactNoopPersistent now have to destructure the object to
list out the names it's going to export. We should probably refactor
ReactNoop away from createReactNoop. Especially since it's also not Flow
typed.
* Switch interactions to star exports
This will have esModule compatibility flag on them. They should ideally
export default instead.
Nothing interesting here except that ReactShallowRenderer currently exports
a class with a static method instead of an object.
I think the public API is probably just meant to be createRenderer but
currently the whole class is exposed. So this means that we have to keep
it as default export. We could potentially also expose a named export for
createRenderer but that's going to cause compatibility issues.
So I'm just going to make that export default.
Unfortunately Rollup and Babel (which powers Jest) disagree on how to
import this. So to make it work I had to move the jest tests to imports.
This doesn't work with module resetting. Some tests weren't doing that
anyway and the rest is just testing ReactShallowRenderer so meh.
The useState hook has always composed the useReducer hook. 1:1 composition like this is fine.
But some more recent hooks (e.g. useTransition, useDeferredValue) compose multiple hooks internally. This breaks react-debug-tools because it causes off-by-N errors when the debug tools re-renders the function.
For example, if a component were to use the useTransition and useMemo hooks, the normal hooks dispatcher would create a list of first state, then callback, then memo hooks, but the debug tools package would expect a list of transition then memo. This can break user code and cause runtime errors in both the react-debug-tools package and in product code.
This PR fixes the currently broken hooks by updating debug tools to be aware of the composite hooks (how many times it should call nextHook essentially) and adds tests to make sure they don't get out of sync again. We'll need to add similar tests for future composite hooks (like useMutableSource #18000).
The testing build versions of react-dom are included in the builds right now, but we're not ready to share them yet. This PR removes them for now (back soon for the next release)
We're not actually building this entry point. I can't think of a reason
we'd need to fork the isomorphic one. We don't really fork it for
anything since it's so generic to work with all renderers.
Since /profiling doesn't have this, it might confuse the story if we made
people alias two things for testing but not profiling.
* Add options for forked entry points
We currently fork .fb.js entry points. This adds a few more options.
.modern.fb.js - experimental FB builds
.classic.fb.js - stable FB builds
.fb.js - if no other FB build, use this for FB builds
.experimental.js - experimental builds
.stable.js - stable builds
.js - used if no other override exists
This will be used to have different ES exports for different builds.
* Switch React to named exports
* Export named exports from the export point itself
We need to re-export the Flow exported types so we can use them in our code.
We don't want to use the Flow types from upstream since it doesn't have the non-public APIs that we have.
This should be able to use export * but I don't know why it doesn't work.
This actually enables Flow typing of React which was just "any" before.
This exposed some Flow errors that needs fixing.
* Create forks for the react entrypoint
None of our builds expose all exports and they all differ in at least one
way, so we need four forks.
* Set esModule flag to false
We don't want to emit the esModule compatibility flag on our CommonJS
output. For now we treat our named exports as if they're CommonJS.
This is a potentially breaking change for scheduler (but all those apis
are unstable), react-is and use-subscription. However, it seems unlikely
that anyone would rely on this since these only have named exports.
* Remove unused Feature Flags
* Let jest observe the stable fork for stable tests
This lets it do the negative test by ensuring that the right tests fail.
However, this in turn will make other tests that are not behind
__EXPERIMENTAL__ fail. So I need to do that next.
* Put all tests that depend on exports behind __EXPERIMENTAL__
Since there's no way to override the exports using feature flags
in .intern.js anymore we can't use these APIs in stable.
The tradeoff here is that we can either enable the negative tests on
"stable" that means experimental are expected to fail, or we can disable
tests on stable. This is unfortunate since some of these APIs now run on
a "stable" config at FB instead of the experimental.
* Switch ReactDOM to named exports
Same strategy as React.
I moved the ReactDOMFB runtime injection to classic.fb.js
Since we only fork the entrypoint, the `/testing` entrypoint needs to
be forked too to re-export the same things plus `act`. This is a bit
unfortunate. If it becomes a pattern we can consider forking in the
module resolution deeply.
fix flow
* Fix ReactDOM Flow Types
Now that ReactDOM is Flow type checked we need to fix up its types.
* Configure jest to use stable entry for ReactDOM in non-experimental
* Remove additional FeatureFlags that are no longer needed
These are only flagging the exports and no implementation details so we
can control them fully through the export overrides.
* [eslint-plugin-react-hooks] Fix cyclic caching for loops containing a condition
* [eslint-plugin-react-hooks] prettier write
* [eslint-plugin-react-hooks] Fix set for tests
* Update packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
Co-Authored-By: Luke Kang <kidkkr@icloud.com>
Co-authored-by: Luke Kang <kidkkr@icloud.com>
* Test automation for edge dev tools extension
* Linter changes
* Load extension automatically.
* Fixed path in `test` command
Co-authored-by: Brian Vaughn <brian.david.vaughn@gmail.com>
Exports from ReactDOM represents React's public API. This include types
exported by React. At some point we'll start building Flow types from
these files.
The duplicate name between DOMContainer and Container seems confusing too
since it was used in the same files even though they're the same.
* import * as React from "react";
This is the correct way to import React from an ES module since the ES
module will not have a default export. Only named exports.
* import * as ReactDOM from "react-dom"
I recently landed a change to the timing of passive effect cleanup functions during unmount (see #17925). This change defers flushing of passive effects for unmounted components until later (whenever we next flush pending passive effects).
Since this change increases the likelihood of a (not actionable) state update warning for unmounted components, I've suppressed that warning for Fibers that have scheduled passive effect unmounts pending.
Fixes a bug where lower priority updates on a components wrapped with
`memo` are sometimes left dangling in the queue without ever being
processed, if they are preceded by a higher priority bailout.
Cause
-----
The pending update priority field is cleared at the beginning of
`beginWork`. If there is remaining work at a lower priority level, it's
expected that it will be accumulated on the work-in-progress fiber
during the begin phase.
There's an exception where this assumption doesn't hold:
SimpleMemoComponent contains a bailout that occurs *before* the
component is evaluated and the update queues are processed, which means
we don't accumulate the next priority level. When we complete the fiber,
the work loop is left to believe that there's no remaining work.
Mitigation
----------
Since this only happens in a single case, a late bailout in
SimpleMemoComponent, I've mitigated the bug in that code path by
restoring the original update priority from the current fiber.
This same case does not apply to MemoComponent, because MemoComponent
fibers do not contain hooks or update queues; rather, they wrap around
an inner fiber that may contain those. However, I've added a test case
for MemoComponent to protect against a possible future regression.
Possible next steps
-------------------
We should consider moving the update priority assignment in `beginWork`
out of the common path and into each branch, to avoid similar bugs in
the future.
Adds a feature flag for when React.jsx warns you about spreading a key into jsx. It's false for all builds, except as a dynamic flag for fb/www.
I also included the component name in the warning.
This warning already exists for class components, but not for functions.
It does not apply to render phase updates to the same component, which
have special semantics that we do support.
Our current lint config assumes a browser environment, which means it won't warn you if you use a variable like `name` without declaring it earlier. This imports the same list as the one used by create-react-app, and enables it against our codebase.
* Re-throw errors thrown by the renderer at the root
React treats errors thrown at the root as a fatal because there's no
parent component that can capture it. (This is distinct from an
"uncaught error" that isn't wrapped in an error boundary, because in
that case we can fall back to deleting the whole tree -- not great, but
at least the error is contained to a single root, and React is left in a
consistent state.)
It turns out we didn't have a test case for this path. The only way it
can happen is if the renderer's host config throws. We had similar test
cases for host components, but none for the host root.
This adds a new test case and fixes a bug where React would keep
retrying the root because the `workInProgress` pointer was not advanced
to the next fiber. (Which in this case is `null`, since it's the root.)
We could consider in the future trying to gracefully exit from certain
types of root errors without leaving React in an inconsistent state. For
example, we should be able to gracefully exit from errors thrown in the
begin phase. For now, I'm treating it like an internal invariant and
immediately exiting.
* Add comment
* Split recent passive effects changes into 2 flags
Separate flags can now be used to opt passive effects into:
1) Deferring destroy functions on unmount to subsequent passive effects flush
2) Running all destroy functions (for all fibers) before create functions
This allows us to test the less risky feature (2) separately from the more risky one.
* deferPassiveEffectCleanupDuringUnmount is ignored unless runAllPassiveEffectDestroysBeforeCreates is true
Before attempting to land an expiration times refactor, I want to see
if this particular change will impact performance (either positively
or negatively). I will test this with a GK.
This babel transform is a fork of the @babel/plugin-transform-react-jsx transform and is for experimentation purposes only. We don't plan to own this code in the future, and we will upstream this to Babel at some point once we've proven out the concept.
As per the RFC to simplify element creation, we want to add the ability to auto import "react' directly from the babel plugin. This commit updates the babel plugin with two options:
1.) importSource: The React module to import from. Defaults to react.
2.) autoImport: The type of import. Defaults to none.
- none: Does not import React. JSX compiles to React.jsx etc.
- namespace: import * as _react from "react";. JSX compiles to _react.jsx etc.
- default: import _default from "react"; JSX compiles to _default.jsx etc.
- namedExports: import {jsx as _jsx} from "react"; JSX compiles to _jsx etc.
- require: var _react = _interopRequireWildcard(require("react"));. jSX compiles to _react.jsx etc.
namespace, default, and namedExports can only be used when sourceType: module and require can only be used when sourceType: script.
It also adds two pragmas (jsxAutoImport and jsxImportSource) that allow users to specify autoImport and importSource in the docblock.
* Build both stable and experimental WWW builds
* Flip already experimental WWW flags to true
* Remove FB-specific internals from modern FB builds
We think we're not going to need these.
* Disable classic features in modern WWW builds
* Disable legacy ReactDOM API for modern WWW build
* Don’t include user timing in prod
* Fix bad copy paste and add missing flags to test renderer
* Add testing WWW feature flag file
We need it because WWW has a different meaning of experimental now.
This section is empty, and imo isn't really helpful in React's changelog. I'm honestly not sure why this is even here? Figured I'd start a discussion with a PR, or we can remove it right now.
* Flush all passive destroy fns before calling create fns
Previously we only flushed destroy functions for a single fiber.
The reason this is important is that interleaving destroy/create effects between sibling components might cause components to interfere with each other (e.g. a destroy function in one component may unintentionally override a ref value set by a create function in another component).
This PR builds on top of the recently added deferPassiveEffectCleanupDuringUnmount kill switch to separate passive effects flushing into two separate phases (similar to layout effects).
* Change passive effect flushing to use arrays instead of lists
This change offers a small advantage over the way we did things previous: it continues invoking destroy functions even after a previous one errored.
The mock Scheduler that we use in our tests has its own fake timer
implementation. The `unstable_advanceTime` method advances the timeline.
Currently, a call to `unstable_advanceTime` will also flush any pending
expired work. But that's not how it works in the browser: when a timer
fires, the corresponding task is added to the Scheduler queue. However,
we will still wait until the next message event before flushing it.
This commit changes `unstable_advanceTime` to more closely resemble the
browser behavior, by removing the automatic flushing of expired work.
```js
// Before this commit
Scheduler.unstable_advanceTime(ms);
// Equivalent behavior after this commit
Scheduler.unstable_advanceTime(ms);
Scheduler.unstable_flushExpired();
```
The general principle is to prefer separate APIs for scheduling tasks
and flushing them.
This change does not affect any public APIs. `unstable_advanceTime` is
only used by our own test suite. It is not used by `act`.
However, we may need to update tests in www, like Relay's.
* apply changes on editablevalue on blur feature implemented
* Removed "Undo" button and unnecessary event.preventDefault()
Co-authored-by: Brian Vaughn <brian.david.vaughn@gmail.com>
This PR introduces adds `react/testing` and `react-dom/testing`.
- changes infra to generate these builds
- exports act on ReactDOM in these testing builds
- uses the new test builds in fixtures/dom
In the next PR -
- I'll use the new builds for all our own tests
- I'll replace usages of TestUtils.act with ReactDOM.act.
* Simplify Continuous Hydration Targets
Let's use a constant priority for this. This helps us avoid restarting
a render when switching targets and simplifies the model.
The downside is that now we're not down-prioritizing the previous hover
target. However, we think that's ok because it'll only do one level too
much and then stop.
* Add test meant to show why it's tricky to merge both hydration levels
Having both levels co-exist works. However, if we deprioritize hydration
using a single level, we might deprioritize the wrong thing.
This adds a test that catches it if we ever try a naive deprioritization
in the future.
It also tests that we don't down-prioritize if we're changing the hover
in the middle of doing continuous priority work.
* Flush useEffect clean up functions in the passive effects phase
This is a change in behavior that may cause broken product code, so it has been added behind a killswitch (deferPassiveEffectCleanupDuringUnmount)
* Avoid scheduling unnecessary callbacks for cleanup effects
Updated enqueuePendingPassiveEffectDestroyFn() to check rootDoesHavePassiveEffects before scheduling a new callback. This way we'll only schedule (at most) one.
* Updated newly added test for added clarity.
* Cleaned up hooks effect tags
We previously used separate Mount* and Unmount* tags to track hooks work for each phase (snapshot, mutation, layout, and passive). This was somewhat complicated to trace through and there were man tag types we never even used (e.g. UnmountLayout, MountMutation, UnmountSnapshot). In addition to this, it left passive and layout hooks looking the same after renders without changed dependencies, which meant we were unable to reliably defer passive effect destroy functions until after the commit phase.
This commit reduces the effect tag types to only include Layout and Passive and differentiates between work and no-work with an HasEffect flag.
* Disabled deferred passive effects flushing in OSS builds for now
* Split up unmount and mount effects list traversal
Update various parts of DevTools to account for the fact that the global "hook" might be undefined if DevTools didn't inject it (due to the page's `contentType`) it (due to the page's `contentType`)
This reverts commit 01974a867c.
* Failing test: Expiring a partially completed tree
We should not throw out a partially completed tree if it expires in the
middle of rendering. We should finish the rest of the tree without
yielding, then finish any remaining expired levels in a single batch.
* Check if there's a partial tree before restarting
If a partial render expires, we should stay in the concurrent path
(performConcurrentWorkOnRoot); we'll stop yielding, but the rest of the
behavior remains the same.
We will only revert to the sync path (performSyncWorkOnRoot) when
starting on a new level.
This approach prevents partially completed concurrent work from
being discarded.
* New test: retry after error during expired render
* Add test of Event Replaying using Flare
* Fix Event Replaying in Flare by Eagerly Adding Active Listeners
This effectively reverts part of https://github.com/facebook/react/pull/17513
* Failing test: Expiring a partially completed tree
We should not throw out a partially completed tree if it expires in the
middle of rendering. We should finish the rest of the tree without
yielding, then finish any remaining expired levels in a single batch.
* Check if there's a partial tree before restarting
If a partial render expires, we should stay in the concurrent path
(performConcurrentWorkOnRoot); we'll stop yielding, but the rest of the
behavior remains the same.
We will only revert to the sync path (performSyncWorkOnRoot) when
starting on a new level.
This approach prevents partially completed concurrent work from
being discarded.
* New test: retry after error during expired render
The changes to the test code relate to changes in JSDOM that come with Jest 25:
* Several JSDOM workarounds are no longer needed.
* Several tests made assertions to match incorrect JSDOM behavior (e.g. setAttribute calls) that JSDOM has now patched to match browsers.
* https://codesandbox.io/s/resets-value-of-datetime-input-to-fix-bugs-in-ios-safari-1ppwh
* JSDOM no longer triggers default actions when dispatching click events.
* https://codesandbox.io/s/beautiful-cdn-ugn8f
* JSDOM fixed (jsdom/jsdom#2700) a bug so that calling focus() on an already focused element does not dispatch a FocusEvent.
* JSDOM now supports passive events.
* JSDOM has improved support for custom CSS properties.
* But requires jsdom/cssstyle#112 to land to support webkit prefixed properties.
When owner and self are different for string refs, we can't easily convert them to callback refs. This PR adds a warning for string refs when owner and self are different to tell users to manually update these refs.
I moved unstable_SuspenseList internally. We don't need the FB build.
I plan on also removing the ReactDOM fb specific entry. We shouldn't add
any more FB specific internals nor APIs. If they're experimental they
should go onto the experimental builds to avoid too many permutations.
* Remove renderPhaseUpdates Map
Follow up to #17484, which was reverted due to a bug found in www.
* Failing test: Dropped updates
When resetting render phase updates after a throw, we should only clear
the pending queue of hooks that were already processed.
* Fix non-render-phase updates being dropped
Detects if a queue has been processed by whether the hook was cloned.
If we change the implementation to an array instead of a list, we'll
need some other mechanism to determine whether the hook was processed.
* Regression test: startTransition in render phase
useTransition uses the state hook as part of its implementation, so we
need to fork it in the dispatcher used for re-renders, too.
* Update Flow to 0.84
* Fix violations
* Use inexact object syntax in files from fbsource
* Fix warning extraction to use a modern parser
* Codemod inexact objects to new syntax
* Tighten types that can be exact
* Revert unintentional formatting changes from codemod
* Remove toString of dangerouslySetInnerHTML
As far as I can tell, the toString call was added here:
caae627cd5 (diff-5574f655d491348f422bca600ff6711dR887)
It was never really needed. Subsequently when we added Trusted Types,
this needed to be changed to a special call but we really should just
always let it pass through.
* Remove special casing of toString values when enableTrustedTypesIntegration
As far as I can tell, we only toString in user space because of IE8/9.
We don't really support IE8/9 anymore and by the time this flag is on,
we should be able to deprecate it.
Unless this is also an issue in IE11. I haven't tested yet.
* Revert "Revert "Dispatch commands to both UIManagers from both renderers (#17211)" (#17232)"
This reverts commit d0fc0ba0a6.
* Clean up another __DEV__ warning check
Previously, DevTools filtered empty commits on the backend, while profiling, through the use of a bailout heuristic that React currently happens to use. This approach was brittle and may have exacerbated the long-standing Profiler bug #16446.
This PR removes that heuristic and adds as a post-processing filtering pass instead. This removes the coupling between DevTools and a React internal implementation detail that may change.
I believe DevTools has two choices of criteria for this filtering:
* Filter commits that have no actual duration metadata.
* Filter commits that have no recorded operations (no mutations to the tree, no changed tree base durations).
I chose the first option, filtering by commits that have no reported metadata. It will miss an edge case, e.g. , but we would have nothing meaningful to show in the Profiler for those cases anyway. (This particular edge case is why one of the snapshots changed with this commit.)
The second option, filtering by recorded operations, could potentially miss a more important edge case: where a component *did* render, but its didn't change. (In that event, there would be no operations to send.)
As far as I can tell, the toString call was added here:
caae627cd5 (diff-5574f655d491348f422bca600ff6711dR887)
It was never really needed. Subsequently when we added Trusted Types,
this needed to be changed to a special call but we really should just
always let it pass through.
stateNode is not one of the fields that gets copied over by createWorkInProgress.
This is bad for persistent mode since it's not the same instance.
In HostComponent we happened to always end up transferring the current stateNode when we bail.
However, we didn't do this for HostText.
DevTools previously called in several places with user-defined values. This could lead to runtime errors if those values had an overriden attribute. This commit replaces those callse with instead.
New test cases have been added.
The Profiler stores:
1. A snapshot of the React tree when profiling started
2. The operations array for each commit
3. Profiling metadata (e.g. durations, what changed, etc) for each commit
It uses this information (snapshot + operations diff) to reconstruct the state of the application for a given commit as it's viewed in the Profiler UI. Because of this, it's very important that the operations and metadata arrays align. If they don't align, the profiler will be unable to correctly reconstruct the tree, and it will likely throw errors (like 'Could not find node…')
#16446 tracks a long-standing bug where these two arrays get misaligned. I am still not entirely sure what causes this bug, but with PR #17253, I exacerbated things by introducing another potential way for it to happen. This PR addresses the regression at least (and adds test coverage for it).
I will follow up this afternoon on the original #16446 issue. I think I may have a lead on what's happening at least, if not exactly an idea of how to reproduce it.
I used to disable the <- and -> buttons when you reached the beginning or end of the profiler data. This can be kind of annoying though when you just want to get to the last commit, and I don't think there's a good reason to enforce it anyway, so I backed that change out. The buttons now wrap around at the beginning or end of the list.
The param should probably be a generic type, but I'm not sure how to satisfy Flow with the current top-level Map. At least this adds basic coverage (which was missing before, oops).
Previously, when props/state contained a regexp, it was shown as an
empty object. This commit adds regexps as values in need of special
rehydration (like Symbols or TypedArrays), and display them as a user
might expect.
Co-authored-by: Zirak <zirakertan@gmail.com>
Moves the unit testing library for events into the `packages` directory so it can more easily be used in tests for other react packages, and mirrored internally to help with testing of event hooks we prototype in www.
Introduces a state machine around pointer events to produce more accurate mock
touch events. This allows multi-touch unit tests to be written entirely in
terms of mock pointer interactions, while producing the expected
'changedTouches', 'targetTouches', and 'touches' fields for mock touch events.
* Updated DevTools local development instructions to mention experimental build step
* Added a command to download latest experimental release (for DevTools)
* Updated build instructions for clarity
* Added build-for-devtools package alias
* Added rudimentary context menu hook and menu UI
* Added backend support for copying a value at a specific path for the inspected element
* Added backend support for storing a value (at a specified path) as a global variable
* Added special casing to enable copying undefined/unserializable values to the clipboard
* Added copy and store-as-global context menu options to selected element props panel
* Store global variables separately, with auto-incremented name (like browsers do)
* Added tests for new copy and store-as-global backend functions
* Fixed some ownerDocument/contentWindow edge cases
* Refactored context menu to support dynamic options
Used this mechanism to add a conditional menu option for inspecting the current value (if it's a function)
* Renamed "safeSerialize" to "serializeToString" and added inline comment
* Add feature flags
* Add Chunk type and constructor
* Wire up Chunk support in the reconciler
* Update reconciler to reconcile Chunks against the render method
This allows the query and args to be updated.
* Drop the ref. Chunks cannot have refs anyway.
* Add Chunk checks in more missing cases
* Rename secondArg
* Add test and fix lazy chunks
Not really a supported use case but for consistency I guess.
* Fix fragment test
* Favor fallthrough switch instead of case statements for work tags
Currently we're inconsistently handling tags that are only relevant
for certain flags. We should throw if the tag is not part of the built
feature flags. This should also mean that the case statements can be
eliminated.
We can achieve this effect by putting the invariant outside of the switch
and always early return in the switch. We already do this in beginWork.
This PR makes this consistent in other places.
* Fail if fundamental/scope tags are discovered without the flag on
* fix(dev-tools): fix show correct displayName with forwardRef in Dev Tools
allow set `displayName` after `React.forwardRef()`,
makesure Dev Tools show displayName as same as `getWrappedName` in `shared/getComponentName.js`
* Removed a little unnecessary/redundant code.
* Fixed lint error (removed unused var)
1. Enable nested values to be expanded/collapsed by clicking on values as well as keys.
2. Enable keys and values to be selectable (for copy-pasting purposes)
* Skip abandoned project folders in Jest config
This fixes a problem that occurs after renaming a package.
* Fix test_build_devtools to run test-build-devtools
* Exclude console.error plugin for DevTools packages
* Use correct release channel for DevTools tests
This should fix the createRoot error.
* Fix TZ dependent test
* Change DT job dependencies
* Replace all warning/lowPriWarning with console calls
* Replace console.warn/error with a custom wrapper at build time
* Fail the build for console.error/warn() where we can't read the stack
* Render phase updates can now be extracted from the pending queue
* Use a custom dispatcher for the second render pass
* Discard render phase updates if component throws
When aborting a render, we also need to throw out render phase updates.
Remove the updates from the queues so they do not persist to the next
render. We already did a single pass through the whole list of hooks, so
we know that any pending updates must have been dispatched during the
render phase. The ones that were dispatched before we started rendering
were already transferred to the current hook's queue.
* Improved inspected element props with inline previews
This mimics the inline preview shown by the brower console and dramatically improves the UX when inspecting deep values. I also updated tests to add more coverage for this new functionality.
* Cleaned up the DataView vs typed array check
* Added early bailouts to DevTools when generating preview strings for iterables/objects/arrays, to avoid doing unnecessary work
* prep for codemod
* prep warnings
* rename lint rules
* codemod for ifs
* shim www functions
* Handle more cases in the transform
* Thanks De Morgan
* Run the codemod
* Delete the transform
* Fix up confusing conditions manually
* Fix up www shims to match expected API
* Also check for low-pri warning in the lint rule
* Refactor Update Queues to Fix Rebasing Bug
Fixes a bug related to rebasing updates. Once an update has committed,
it should never un-commit, even if interrupted by a higher priority
update. The fix includes a refactor of how update queues work.
This commit is a combination of two PRs:
- #17483 by @sebmarkbage refactors the hook update queue
- #17510 by @acdlite refactors the class and root update queue
Landing one without the other would cause state updates to sometimes be
inconsistent across components, so I've combined them into a single
commit in case they need to be reverted.
Co-authored-by: Sebastian Markbåge <sema@fb.com>
Co-authored-by: Andrew Clark <git@andrewclark.io>
* Initialize update queue object on mount
Instead of lazily initializing update queue objects on the first update,
class and host root queues are created on mount. This simplifies the
logic for appending new updates and matches what we do for hooks.
Reverts b617db3d96.
Found some bugs when attempting to land in www. Reverting to fix master.
I'll land again *after* the change successfully land downstream.
Fixes a bug related to rebasing updates. Once an update has committed,
it should never un-commit, even if interrupted by a higher priority
update. The fix includes a refactor of how update queues work.
This commit is a combination of two PRs:
- #17483 by @sebmarkbage refactors the hook update queue
- #17510 by @acdlite refactors the class and root update queue
Landing one without the other would cause state updates to sometimes be
inconsistent across components, so I've combined them into a single
commit in case they need to be reverted.
Co-authored-by: Sebastian Markbåge <sema@fb.com>
Co-authored-by: Andrew Clark <git@andrewclark.io>
Tools like BetterTouchTool for macOS trigger middle-clicks with a 'buttons'
value that doesn't correspond to the middle-mouse button. To account for this
we also inspect the value of 'button'.
Close#17367
* Replace Babel plugin with an ESLint plugin
* Fix ESLint rule violations
* Move shared conditions higher
* Test formatting nits
* Tweak ESLint rule
* Bugfix: inside else branch, 'if' tests are not satisfactory
* Use a stricter check for exactly if (__DEV__)
This makes it easier to see what's going on and matches dominant style in the codebase.
* Fix remaining files after stricter check
* fix: make serializable data for bridge in react-devtools
* fix: add bigint data type in hydration
* refactor: remove console.log
* test: update unit tests for bigint in react-devtools
* We don't need the global state for this
* Move componentUpdateQueue and sideEffectTag out of global state
* Move firstWorkInProgressHook off global state
* Move remainingExpirationTime off global state
* Reset fiber to its current state if it throws
* Move rerender error check to avoid global state
This means that it's harder to find it since it's not in the dispatch
function's stack but we can add a DEV only one for that if we really
need it. Alternatively, we can check it in against the renderUpdates queue.
* Move next___Hook out of global state
* Assert that currentlyRenderingFiber is always set
When accessed, this should always be set. This could enforced by storing
this on the dispatcher for example.
* Add another test just to be safe
* Adjust SuspenseList CPU bound heuristic
In SuspenseList we switch to rendering fallbacks (or stop rendering further
rows in the case of tail="collapsed/hidden") if it takes more than 500ms
to render the list. The limit of 500ms is similar to the train model and
designed to be short enough to be in the not noticeable range.
This works well if each row is small because we time the 500ms range well.
However, if we have a few large rows then we're likely to exceed the limit
by a lot. E.g. two 480ms rows hits almost a second instead of 500ms.
This PR adjusts the heuristic to instead compute whether something has
expired based on the render time of the last row. I.e. if we think rendering
one more row would exceed the timeout, then we don't attempt.
This still works well for small rows and bails earlier for large rows.
The expiration is still based on the start of the list rather than the
start of the render. It should probably be based on the start of the render
but that's a bigger change and needs some thought.
* Comment
* [Fresh] Detect root updates more reliably
* [Fresh] Use WeakMap for root elements
* [Fresh] Make initial failures recoverable too
* Fix DevTools check
* Fix wrong flow type
* [eslint] Check forwardRef callbacks (#17220)
* [eslint] Make tests more realistic (#17220)
* [eslint] Check anonymous callback of React.memo for rules-of-hooks (#17220)
* [eslint] Add tests for callbacks not known to be components (#17220)
* [eslint] Correct comments and add another test (#17220)
Fixes a bug where `isPending` is only set to `true` if `startTransition`
is called from inside an input event. That's usually the case, but
not always.
Now it works regardless of where you call it.
* Move Flight DOM to Webpack Specific Packagee
We'll have Webpack specific coupling so we need to ensure that it can be
versioned separately from various Webpack versions. We'll also have builds
for other bundlers in the future.
* Move to peerDep
* Move DOM Flight Tests
* Merge ReactFlightIntegration into ReactFlightDOM
This was an integration test. We can add to it.
* Fix fixture paths
* Regression test: Effects dropped across roots
See #17066
* [Bugfix] Passive effects loop
The bug
-------
In a multi-root app, certain passive effects (`useEffect`) are never
fired. See #17066.
The underlying problem
----------------------
The implicit contract of `flushPassiveEffects` is that, right after
calling it, there should be no pending passive effects. In the normal
case, in concurrent mode, this is true. But the current implementation
fails to account for the case where a passive effect schedules
synchronous work, which in turn schedules additional passive effects.
This led to `rootWithPendingPassiveEffects` being overwritten in the
commit phase, because an assignment that assumed it was replacing null
was actually replacing a reference to another root, which has the
consequence of dropping passive effects on that root.
The fix
-------
The fix I've chosen here is, at the beginning of the commit phase, keep
flushing passive effects in a loop until there are no more.
This doesn't not change the "public" implementation of
`flushPassiveEffects`, though it arguably should work this way, too. I
say "public" because it's only used by implementation layers on top of
React which we control: mainly, the legacy version of `act` that does
not use the mock Scheduler build. So there's probably still a bug
in that `act` implementation.
I will address `act` in a follow-up. The ideal solution is to replace
the legacy `act` with one implemented directly in the renderer, using a
special testing-only build of React DOM. Since that requires a breaking
change, we'll need an interim solution. We could make the "public" `act`
recursively flush effects in a loop, as I've done for the commit phase.
However, I think a better solution is to stop automatically flushing the
synchronous update queue at the end of `flushPassiveEffects`, and
instead require the caller to explicitly call `flushSyncUpdateQueue` (or
the equivalent) if needed. This follows the same pattern we use
internally in the work loop, which is designed to avoid factoring
hazards like the one that resulted in this bug.
* Unify fields used for createRoot warning and event system
* Warn when doing createRoot twice on the same node
* Stricter check for modern roots
* Unmark asynchronously
* Fix Flow
* [Flight] Basic Integration Test
* Just act()
* Lint
* Remove unnecessary acts
* Use Concurrent Mode
* it.experimental
* Fix prod test by advancing time
* Don't observe initial state
* Return whether to keep flowing in Host config
* Emit basic chunk based streaming in the Flight server
When something suspends a new chunk is created.
* Add reentrancy check
The WHATWG API is designed to be pulled recursively.
We should refactor to favor that approach.
* Basic streaming Suspense support on the client
* Add basic suspense in example
* Add comment describing the protocol that the server generates
1. Add a Store test for memo, lazy, and forwardRef components
2. Remove dead code for React.lazy
3. Update DT tests to include HOC badge names in the serialized store
* [react-is] return correct typeOf value of forwardRef
* [react-devtools-shared] use correct displayName of memo(forwardRef(Component))
* [react-devtools-shared] add resolveFiberType and resolve fiber type of memo recursively
Resolving the fiber type of memo recursively before passing it to getDisplayName
will prevent it from displaying "Anonymous" as displayName for components
wrapped with both memo and forwardRef: memo(forwardRef(Component))
* rework resolveFiberType
There are two similar flags, `debugRenderPhaseSideEffects` and
`debugRenderPhaseSideEffectsForStrictMode`. The strict mode one is the
only one that is actually used. I think originally the theory is that
we would one day turn it on for all components, even outside strict
mode. But what we'll do instead is migrate everyone to strict mode.
The only place `debugRenderPhaseSideEffects` was being used was in
an internal test file. I rewrote those tests to use public APIs.
* Rename ReactFlightStreamer -> ReactFlightServer
* Unify Browser/Node stream tests into one file and use the client reader
* Defer to the actual ReactDOM for HTML rendering for now
This will need to use a variant of Fizz to do inline SSR in Flight.
However, I don't want to build the whole impl right now but also don't
want to exclude the use case yet. So I outsource it to the existing
renderer. Ofc, this doesn't work with Suspense atm.
* Change demo to server
* Expose client in package.json
* Reorganize tests
We don't want unit tests but instead test how both server and clients work
together. So this merges server/client test files.
* Fill in the client implementation a bit
* Use new client in fixture
* Add Promise/Uint8Array to lint rule
I'll probably end up deleting these deps later but they're here for now.
`it.experimental` marks that a test only works in Experimental builds.
It also asserts that a test does *not* work in the stable builds. The
main benefit is that we're less likely to accidentally expose an
experimental API before we intend. It also forces us to un- mark an
experimental test once it become stable.
* Add CodeSandbox CI Config
* Add default sandbox to build
* Make build more efficient and add scheduler
* Force build
* Add scheduler image
* Add scheduler/tracing to the build
* Force another build
* Add Flight Build and Unify HostFormat Config between Flight and Fizz
* Add basic resolution of models
* Add basic Flight fixture
Demonstrates the streaming protocol.
* Rename to flight-server to distinguish from the client parts
* Add Flight Client package and entry point
* Fix fixture
Already mounted rows that resuspend may be considered as part of a tail
if they're at the end. However, for purposes of the tail="..." option
they don't get deleted. We deal with that in cutOffTailIfNeeded.
However, if they're also the first to suspend in the "hidden" case, we have
a special case that deletes the actual rendered row. This needs to consider
if that row was already mounted or things go wrong.
* Failing test: DevTools hook freezes timeline
The DevTools hook calls `requestCurrentTime` after the commit phase has
ended, which has the accidnental consequence of freezing the start
time for subsequent updates. If enough time goes by, the next update
will instantly expire.
I'll push a fix in the next commit.
* Read current time without marking event start time
`requestCurrentTime` is only meant to be used for updates, because
subsequent calls within the same event will receive the same time.
Messing this up has bad consequences.
I renamed it to `requestCurrentTimeForUpdate` and created a new
function that returns the current time without the batching heuristic,
called `getCurrentTime`.
Swapping `requestCurrentTime` for `getCurrentTime` in the DevTools
hook fixes the regression test added in the previous commit.
Special version of Jest's `it` for experimental tests. Tests marked as
experimental will run **both** stable and experimental modes. In
experimental mode, they work the same as the normal Jest methods. In
stable mode, they are **expected to fail**. This means we can detect
when a test previously marked as experimental can be un-marked when the
feature becomes stable. It also reduces the chances that we accidentally
add experimental APIs to the stable builds before we intend.
I added corresponding methods for the focus and skip APIs:
- `fit` -> `fit.experimental`
- `it.only` -> `it.only.experimental` or `it.experimental.only`
- `xit` -> `xit.experimental`
- `it.skip` -> `it.skip.experimental` or `it.experimental.skip`
Since `it` is an alias of `test`, `test.experimental` works, too.
`yarn build` defaults to building in experimental mode. To opt-out, set
the `RELEASE_CHANNEL` environment variable to `stable`. This is the same
as what we do when running tests via `yarn test`, to make local
development easier.
* SuspenseList support in DevTools
This adds SuspenseList tags to DevTools so that the name properly shows
up.
It also switches to use the tag instead of Symbol type for Suspense
components. We shouldn't rely on the type for any built-ins since that
field will disappear from the fibers. How the Fibers get created is an
implementation detail that can change e.g. with a compiler or if we
use instanceof checks that are faster than symbol comparisons.
* Add SuspenseList test to shell app
* Add a failing test for SuspenseList bug
* Store lastEffect before rendering
We can't reset the effect list to null because we don't rereconcile the
children so we drop deletion effects if we do that.
Instead we store the last effect as it was before we started rendering
so we can go back to where it was when we reset it.
We actually already do something like this when we delete the last row
for the tail="hidden" mode so we had a field available for it already.
Without the enableSuspenseServerRenderer flag there will never be a boundary match. Also when it is enabled, there might not be a boundary match if something was conditionally rendered by mistake.
With this PR it will now client render the content of a Suspense boundary in that case and issue a DEV only hydration warning. This is the only sound semantics for this case.
Unfortunately, landing this will once again break #16938. It will be less bad though because at least it'll just work by client rendering the content instead of hydrating and issue a DEV only warning.
However, we must land this before enabling the enableSuspenseServerRenderer flag since it does this anyway.
I did notice that we special case fallback={undefined} due to our unfortunate semantics for that. So technically a workaround that works is actually setting the fallback to undefined on the server and during hydration. Then flip it on only after hydration. That could be a workaround if you want to be able to have a Suspense boundary work only after hydration for some reason.
It's kind of unfortunate but at least those semantics are internally consistent. So I added a test for that.
This changes the "default" retryTime to NoWork which schedules at Normal
pri.
Dehydrated bouundaries normally hydrate at Never priority except when they
retry where we accidentally increased them to Normal because Never was used
as the default value. This changes it so NoWork is the default.
Dehydrated boundaries however get initialized to Never as the default.
Therefore they now hydrate as Never pri unless their priority gets
increased by a forced rerender or selective hydration.
This revealed that erroring at this Never priority can cause an infinite
rerender. So I fixed that too.
If a JSX element has both a children prop and children (ie. <div children={childOne}>{childTwo}</div>), IE throws an Multiple definitions of a property not allowed in strict mode. This modifies the previous fix (which used an Object.assign) by making the duplicate children a sequence expression on the next prop/child instead so that ordering is preserved. For example:
```
<Component children={useA()} foo={useB()} children={useC()}>{useD()}</Component>
```
should compile to
```
React.jsx(Component, {foo: (useA(), useB()), children: (useC(), useD)})
```
I'm doing this here instead of in the downstream repo so that if the
sync diff gets reverted, it doesn't revert this, too.
Once the sync has landed, and the callers are updated in www, I will
remove this.
* Tests run in experimental mode by default
For local development, you usually want experiments enabled. Unless
the release channel is set with an environment variable, tests will
run with __EXPERIMENTAL__ set to `true`.
* Remove concurrent APIs from stable builds
Those who want to try concurrent mode should use the experimental
builds instead.
I've left the `unstable_` prefixed APIs in the Facebook build so we
can continue experimenting with them internally without blessing them
for widespread use.
* Turn on SSR flags in experimental build
* Remove prefixed concurrent APIs from www build
Instead we'll use the experimental builds when syncing to www.
* Remove "canary" from internal React version string
* Download correct artifacts for release channel
Experimental builds should pull artifacts from the
`process_artifacts_experimental` job.
I think instead of two separate CI workflows, a better approach might
be to build stable artifacts to the `build` directory and the
experimental artifacts to a `build_experimental` directory, and
generate both within the same workflow. This would take some work since
lots of things assume the output directory is `build`, but something
to consider in the future.
* Prevent experimental promotion to stable
Adds a check to the `prepare-stable` script to prevent experimental
builds from being published using stable semver versions.
* Don't bother including `unstable_` in error
The method names don't get stripped out of the production bundles
because they are passed as arguments to the error decoder.
Let's just always use the unprefixed APIs in the messages.
* Set up experimental builds
The experimental builds are packaged exactly like builds in the stable
release channel: same file structure, entry points, and npm package
names. The goal is to match what will eventually be released in stable
as closely as possible, but with additional features turned on.
Versioning and Releasing
------------------------
The experimental builds will be published to the same registry and
package names as the stable ones. However, they will be versioned using
a separate scheme. Instead of semver versions, experimental releases
will receive arbitrary version strings based on their content hashes.
The motivation is to thwart attempts to use a version range to match
against future experimental releases. The only way to install or depend
on an experimental release is to refer to the specific version number.
Building
--------
I did not use the existing feature flag infra to configure the
experimental builds. The reason is because feature flags are designed
to configure a single package. They're not designed to generate multiple
forks of the same package; for each set of feature flags, you must
create a separate package configuration.
Instead, I've added a new build dimension called the **release
channel**. By default, builds use the **stable** channel. There's
also an **experimental** release channel. We have the option to add more
in the future.
There are now two dimensions per artifact: build type (production,
development, or profiling), and release channel (stable or
experimental). These are separate dimensions because they are
combinatorial: there are stable and experimental production builds,
stable and experimental developmenet builds, and so on.
You can add something to an experimental build by gating on
`__EXPERIMENTAL__`, similar to how we use `__DEV__`. Anything inside
these branches will be excluded from the stable builds.
This gives us a low effort way to add experimental behavior in any
package without setting up feature flags or configuring a new package.
* Transfer any pending promises from inner boundary to list
For non-hidden modes, this boundary should commit so this shouldn't be
needed but the nested boundary can make a second pass which forces these
to be recreated without resuspending. In this case, the outer list assumes
that it can collect the inner promises to still rerender if needed.
* Propagate suspense "context" change to nested SuspenseLists
This means that we always rerender any nested SuspenseLists together.
This bug looks similar to the previous one but is not based on the lack of
retry but that the retry only happens on the outer boundary but the inner
doesn't get a retry ping since it didn't know about its own promise after
the second pass.
* Remove "Invariant Violation" from dev errors
When I made the change to compile `invariant` to throw expressions, I
left a small runtime to set the error's `name` property to "Invariant
Violation" to maintain the existing behavior.
I think we can remove it. The argument for keeping it is to preserve
continuity in error logs, but this only affects development errors,
anyway: production error messages are replaced with error codes.
* Pass prod error messages directly to constructor
Updates the `invariant` transform to pass an error message string
directly to the Error constructor, instead of mutating the
message property.
Turns this code:
```js
invariant(condition, 'A %s message that contains %s', adj, noun);
```
into this:
```js
if (!condition) {
throw Error(
__DEV__
? `A ${adj} message that contains ${noun}`
: formatProdErrorMessage(ERR_CODE, adj, noun)
);
}
```
* Updated DevTools shell ignore warning message to account for recent changes in warning text
* Update DevTools console patching to patch the parent window's console rather than the iframe, to more accurately simulate real usage environment
* Remove dormant createBatch experiment
In a hybrid React app with multiple roots, `createBatch` is used to
coordinate an update to a root with its imperative container.
We've pivoted away from multi-root, hybrid React apps for now to focus
on single root apps.
This PR removes the API from the codebase. It's possible we'll add back
some version of this feature in the future.
* Remove unused export
The `performance.now` returns a timestamp in milliseconds as a float.
The browser has the option to adjust the precision of the float, but
it's usually more precise than a millisecond. However, this precision
is lost when the timestamp is logged by the Scheduler profiler, because
we store the numbers in an Int32Array.
This change multiplies the millisecond float value by 1000, giving us
three more degrees of precision.
Adds an API to explicitly prioritize hydrating the path to a particular DOM node without relying on events to do it.
The API uses the current scheduler priority to schedule it. For the same priority, the last one wins. This allows a similar effect as continuous events. This is useful for example to hydrate based on scroll position, or prioritize components that will upgrade to client-rendered-only content.
I considered having an API that explicitly overrides the current target(s). However that makes it difficult to coordinate across components in an app.
This just hydrates one target at a time but if it is blocked on I/O we could consider increasing priority of later targets too.
Currently, when a node suspends, if its subtree contains a portal, the portal is not hidden. This hides portals in the subtree when it's not wrapped in a host component .
* Prioritize the last continuous target
This ensures that the current focus target is always hydrated first.
Slightly higher than the usual Never expiration time used for hydration.
The priority increases with each new queued item so that the last always
wins.
* Don't export the moving target
It's not useful for comparison purposes anyway.
The error transform works by replacing calls to `invariant` with
an `if` statement.
Since we're replacing a call expression with a statement, Babel wraps
the new statement in an immediately-invoked function expression (IIFE).
This wrapper is unnecessary in practice because our `invariant` calls
are always part of their own expression statement.
In the production bundle, the function wrappers are removed by Closure.
But they remain in the development bundles.
This commit updates the transform to confirm that an `invariant` call
expression's parent node is an expression statement. (If not, it throws
a transform error.)
Then, it replaces the expression statement instead of the expression
itself, effectively removing the extraneous IIFE wrapper.
* Regression test: Suspense + hydration + legacy
* Allow Suspense Mismatch on the Client to Silently Proceed
This fixes but isn't actually the semantics that we want this case to have.
* Update useEditableValue to mirror value cahnges
Previously, the hook initialized local state (in useState) to mirror the prop/state value. Updates to the value were ignored though. (Once the state was initialized, it was never updated.) The new hook updates the local/editable state to mirror the external value unless there are already pending, local edits being made.
* Optimistic CHANGELOG update
* Added additional useEditableValue() unit test cases
* Rename lowPriorityWarning to lowPriorityWarningWithoutStack
This maintains parity with the other warning-like functions.
* Duplicate the toWarnDev tests to test toLowPriorityWarnDev
* Make a lowPriorityWarning version of warning.js
* Extract both variants in print-warning
Avoids parsing lowPriorityWarning.js itself as the way it forwards the
call to lowPriorityWarningWithoutStack is not analyzable.
* Idle updates should not be blocked by hidden work
Use the special `Idle` expiration time for updates that are triggered at
Scheduler's `IdlePriority`, instead of `Never`.
The key difference between Idle and Never¹ is that Never work can be
committed in an inconsistent state without tearing the UI. The main
example is offscreen content, like a hidden subtree.
¹ "Never" isn't the best name. I originally called it that because it
"never" expires, but neither does Idle. Since it's mostly used for
offscreen subtrees, we could call it "Offscreen." However, it's also
used for dehydrated Suspense boundaries, which are inconsistent in the
sense that they haven't finished yet, but aren't visibly inconsistent
because the server rendered HTML matches what the hydrated tree would
look like.
* Reset as early as possible using local variable
* Updates in a hidden effect should be Idle
I had made them Never to avoid an extra render when a hidden effect
updates the hidden component -- if they are Idle, we have to render once
at Idle, which bails out on the hidden subtree, then again at Never to
actually process the update -- but the problem of needing an extra
render pass to bail out hidden updates already exists and we should fix
that properly instead of adding yet another special case.
PR #16752 changed how we were injecting the backend script to be done by the content script in order to work around Trusted Type limitations with our previous approach. This may have caused a regression (see #16840) so I'm backing it out to verify.
* Fixed a regression in hooks editor from a recent EditableValue change
* Fixed a reset/state bug in useEditableValue() hook and removed unnecessary useMemo()
* Outline push/pop logic in `renderRoot`
I want to get rid of the the `isSync` argument to `renderRoot`, and
instead use separate functions for concurrent and synchronous render.
As a first step, this extracts the push/pop logic that happens before
and after the render phase into helper functions.
* Extract `catch` block into helper function
Similar to previous commit. Extract error handling logic into
a separate function so it can be reused.
* Fork `renderRoot` for sync and concurrent
Removes `isSync` argument in favor of separate functions.
* Extra "root completion" logic to separate function
Moving this out to avoid an accidental early return, which would
bypass the call to `ensureRootIsScheduled` and freeze the UI.
* Inline `renderRoot`
Inlines `renderRoot` into `performConcurrentWorkOnRoot` and
`performSyncWorkOnRoot`. This lets me remove the `isSync` argument
and also get rid of a redundant try-catch wrapper.
* [suspense][error handling] Add failing unit test
Covers an edge case where an error is thrown inside the complete phase
of a component that is in the return path of a component that suspends.
The second error should also be handled (i.e. able to be captured by
an error boundary.
The test is currently failing because there's a call to
`completeUnitOfWork` inside the main render phase `catch` block. That
call is not itself wrapped in try-catch, so anything that throws is
treated as a fatal/unhandled error.
I believe this bug is only observable if something in the host config
throws; and, only in legacy mode, because in concurrent/batched mode,
`completeUnitOfWork` on fiber that throws follows the "unwind" path
only, not the "complete" path, and the "unwind" path does not call
any host config methods.
* [scheduler][profiler] Start time of delayed tasks
Fixes a bug in the Scheduler profiler where the start time of a delayed
tasks is always 0.
* Remove ad hoc `throw`
Fatal errors (errors that are not captured by an error boundary) are
currently rethrown from directly inside the render phase's `catch`
block. This is a refactor hazard because the code in this branch has
to mirror the code that happens at the end of the function, when exiting
the render phase in the normal case.
This commit moves the throw to the end, using a new root exit status.
* Handle errors that occur on unwind
* Add Event Replaying Infra
* Wire up Roots and Suspense boundaries, to retry events, after they commit
* Replay discrete events in order in a separate scheduler callback
* Add continuous events
These events only replay their last target if the target is not yet
hydrated. That way we don't have to wait for a previously hovered
boundary before invoking the current target.
* Enable tests from before
These tests were written with replaying in mind and now we can properly
enable them.
* Unify replaying and dispatching
* Mark system flags as a replay and pass to legacy events
That way we can check if this is a replay and therefore needs a special
case. One such special case is "mouseover" where we check the
relatedTarget.
* Eagerly listen to all replayable events
To minimize breakages in a minor, I only do this for the new root APIs
since replaying only matters there anyway. Only if hydrating.
For Flare, I have to attach all active listeners since the current
system has one DOM listener for each. In a follow up I plan on optimizing
that by only attaching one if there's at least one active listener
which would allow us to start with only passive and then upgrade.
* Desperate attempt to save bytese
* Add test for mouseover replaying
We need to check if the "relatedTarget" is mounted due to how the old
event system dispatches from the "out" event.
* Fix for nested boundaries and suspense in root container
This is a follow up to #16673 which didn't have a test because it wasn't
observable yet. This shows that it had a bug.
* Rename RESPONDER_EVENT_SYSTEM to PLUGIN_EVENT_SYSTEM
Makes sure that touch events with modifier keys behave the same way as other
pointer types (i.e., does not call `onTapStart` if the gesture begins with a
modifier key held down)
This is because the HostConfig can't be guaranteed to be consistent with
other code such as code that touches the DOM directly.
Ideally we'd have a more systemic solution to this since it will pop
up for other packages later too.
This patch limits the `onTap*` callbacks to the primary pointer button.
Auxiliary button and modified primary button interactions call
`onAuxiliaryTap`, cancel any active tap, and preserve the native behavior.
* prevent firefox marking required textareas invalid
Bug was caused by an IE10/IE11 bugfix dealing with the placeholder attribute and textContent. Solved by avoiding the IE bugfix when textContent was empty.
Closes#16402
* more explicit conditional check for textContent
re: @philipp-spiess code review
* clarify textarea test fixture's expected result
better describe the behavior we are testing for
re: @philipp-spiess code review
* [react-devtools-shared] Added string type check for object name prop in getDisplayName function from utils.js file; tests included;
* Re-added empty string check to getDisplayName()
* Tweaked tests to use real functions
This more closely simulates how the utility is being used in production, and would catch cases like anonymous functions (with empty string names).
This implements 'usePress' in user-space as a combination of 'useKeyboard' and 'useTap'. The existing 'usePress' API is preserved for now. The previous 'usePress' implementation is moved to 'PressLegacy'.
This accounts for all clicks that are natively dispatched following relevant
keyboard interactions (e.g., key is "Enter"), as well as programmatic clicks,
and screen-reader virtual clicks.
* Add trusted types to react on client side
* Implement changes according to review
* Remove support for trusted URLs, change TrustedTypes to trustedTypes
* Add support for deprecated trusted URLs
* Apply PR suggesstions
* Warn only once, remove forgotten check, put it behind a flag
* Move comment
* Fix PR comments
* Fix html toString concatenation
* Fix forgotten else branch
* Fix PR comments
If a Scheduler profile runs without stopping, the event log will grow
unbounded. Eventually it will run out of memory and the VM will throw
an error.
To prevent this from happening, let's automatically stop the profiler
once the log exceeds a certain limit. We'll also print a warning with
advice to call `stopLoggingProfilingEvents` explicitly.
* Support disabling interaction tracing for suspense promises
If a thrown Promise has the __reactDoNotTraceInteractions attribute, React will not wrapped its callbacks to continue tracing any current interaction(s).
* Added optional '__reactDoNotTraceInteractions' attribute to Flow Thenable type
This reverts commit ab4951fc03.
* Track "pending" and "suspended" ranges
A FiberRoot can have pending work at many distinct priorities. (Note: we
refer to these levels as "expiration times" to distinguish the concept
from Scheduler's notion of priority levels, which represent broad
categories of work. React expiration times are more granualar. They're
more like a concurrent thread ID, which also happens to correspond to a
moment on a timeline. It's an overloaded concept and I'm handwaving over
some of the details.)
Given a root, there's no convenient way to read all the pending levels
in the entire tree, i.e. there's no single queue-like structure that
tracks all the levels, because that granularity of information is not
needed by our algorithms. Instead we track the subset of information
that we actually need — most importantly, the highest priority level
that exists in the entire tree.
Aside from that, the other information we track includes the range of
pending levels that are known to be suspended, and therefore should not
be worked on.
This is a refactor of how that information is tracked, and what each
field represents:
- A *pending* level is work that is unfinished, or not yet committed.
This includes work that is suspended from committing.
`firstPendingTime` and `lastPendingTime` represent the range of
pending work. (Previously, "pending" was the same as "not suspended.")
- A *suspended* level is work that did not complete because data was
missing. `firstSuspendedTime` and `lastSuspendedTime` represent the
range of suspended work. It is a subset of the pending range. (These
fields are new to this commit.)
- `nextAfterSuspendedTime` represents the next known level that comes
after the suspended range.
This commit doesn't change much in terms of observable behavior. The one
change is that, when a level is suspended, React will continue working
on the next known level instead of jumping straight to the last pending
level. Subsequent commits will use this new structure for a more
substantial refactor for how tasks are scheduled per root.
* Get next expiration time from FiberRoot
Given a FiberRoot, we should be able to determine the next expiration
time that needs to be worked on, taking into account the levels that
are pending, suspended, pinged, and so on.
This removes the `expirationTime` argument from
`scheduleCallbackForRoot`, and renames it to `ensureRootIsScheduled` to
reflect the new signature. The expiration time is instead read from the
root using a new function, `getNextExpirationTimeToWorkOn`.
The next step will be to remove the `expirationTime` argument from
`renderRoot`, too.
* Don't bind expiration time to render callback
This is a fragile pattern because there's only meant to be a single
task per root, running at a single expiration time. Instead of binding
the expiration time to the render task, or closing over it, we should
determine the correct expiration time to work on using fields we
store on the root object itself.
This removes the "return a continuation" pattern from the
`renderRoot` function. Continuation handling is now handled by
the wrapper function, which I've renamed from `runRootCallback` to
`performWorkOnRoot`. That function is merely an entry point to
`renderRoot`, so I've also removed the callback argument.
So to sum up, at at the beginning of each task, `performWorkOnRoot`
determines which expiration time to work on, then calls `renderRoot`.
And before exiting, it checks if it needs to schedule another task.
* Update error recovery test to match new semantics
* Remove `lastPendingTime` field
It's no longer used anywhere
* Restart on update to already suspended root
If the work-in-progress root already suspended with a delay, then the
current render definitely won't finish. We should interrupt the render
and switch to the incoming update.
* Restart on suspend if return path has an update
Similar to the previous commit, if we suspend with a delay, and
something in the return path has a pending update, we should abort
the current render and switch to the update instead.
* Track the next unprocessed level globally
Instead of backtracking the return path. The main advantage over the
backtracking approach is that we don't have to backtrack from the source
fiber. (The main disadvantages are that it requires another module-level
variable, and that it could include updates from unrelated
sibling paths.)
* Re-arrange slightly to prevent refactor hazard
It should not be possible to perform any work on a root without
calling `ensureRootIsScheduled` before exiting. Otherwise, we could
fail to schedule a callback for pending work and the app could freeze.
To help prevent a future refactor from introducing such a bug, this
change makes it so that `renderRoot` is always wrapped in try-finally,
and the `finally` block calls `ensureRootIsScheduled`.
* Remove recursive calls to `renderRoot`.
There are a few leftover cases where `renderRoot` is called recursively.
All of them are related to synchronously flushing work before its
expiration time.
We can remove these calls by tracking the last expired level on the
root, similar to what we do for other types of pending work, like pings.
* Remove argument from performSyncWorkOnRoot
Read the expiration time from the root, like we do
in performConcurrentWorkOnRoot.
Our infra currently doesn't support loading a separate profiling
build of Scheduler. Until that's fixed, the recommendation is to load
a single build and gate the profiling feature behind a flag.
Alternative to #16659
* Moved backend injection logic to content script
* Moved backend injection logic to content script
* Moved injection logic to content script
* Formatting changes
* remove ability to inject arbitrary scripts
* Removed done(), added some comments explaining the change
* Lint fixes
* Moved inline comment.
* Deleted inject() script since it was no longer being used
* Track "pending" and "suspended" ranges
A FiberRoot can have pending work at many distinct priorities. (Note: we
refer to these levels as "expiration times" to distinguish the concept
from Scheduler's notion of priority levels, which represent broad
categories of work. React expiration times are more granualar. They're
more like a concurrent thread ID, which also happens to correspond to a
moment on a timeline. It's an overloaded concept and I'm handwaving over
some of the details.)
Given a root, there's no convenient way to read all the pending levels
in the entire tree, i.e. there's no single queue-like structure that
tracks all the levels, because that granularity of information is not
needed by our algorithms. Instead we track the subset of information
that we actually need — most importantly, the highest priority level
that exists in the entire tree.
Aside from that, the other information we track includes the range of
pending levels that are known to be suspended, and therefore should not
be worked on.
This is a refactor of how that information is tracked, and what each
field represents:
- A *pending* level is work that is unfinished, or not yet committed.
This includes work that is suspended from committing.
`firstPendingTime` and `lastPendingTime` represent the range of
pending work. (Previously, "pending" was the same as "not suspended.")
- A *suspended* level is work that did not complete because data was
missing. `firstSuspendedTime` and `lastSuspendedTime` represent the
range of suspended work. It is a subset of the pending range. (These
fields are new to this commit.)
- `nextAfterSuspendedTime` represents the next known level that comes
after the suspended range.
This commit doesn't change much in terms of observable behavior. The one
change is that, when a level is suspended, React will continue working
on the next known level instead of jumping straight to the last pending
level. Subsequent commits will use this new structure for a more
substantial refactor for how tasks are scheduled per root.
* Get next expiration time from FiberRoot
Given a FiberRoot, we should be able to determine the next expiration
time that needs to be worked on, taking into account the levels that
are pending, suspended, pinged, and so on.
This removes the `expirationTime` argument from
`scheduleCallbackForRoot`, and renames it to `ensureRootIsScheduled` to
reflect the new signature. The expiration time is instead read from the
root using a new function, `getNextExpirationTimeToWorkOn`.
The next step will be to remove the `expirationTime` argument from
`renderRoot`, too.
* Don't bind expiration time to render callback
This is a fragile pattern because there's only meant to be a single
task per root, running at a single expiration time. Instead of binding
the expiration time to the render task, or closing over it, we should
determine the correct expiration time to work on using fields we
store on the root object itself.
This removes the "return a continuation" pattern from the
`renderRoot` function. Continuation handling is now handled by
the wrapper function, which I've renamed from `runRootCallback` to
`performWorkOnRoot`. That function is merely an entry point to
`renderRoot`, so I've also removed the callback argument.
So to sum up, at at the beginning of each task, `performWorkOnRoot`
determines which expiration time to work on, then calls `renderRoot`.
And before exiting, it checks if it needs to schedule another task.
* Update error recovery test to match new semantics
* Remove `lastPendingTime` field
It's no longer used anywhere
* Restart on update to already suspended root
If the work-in-progress root already suspended with a delay, then the
current render definitely won't finish. We should interrupt the render
and switch to the incoming update.
* Restart on suspend if return path has an update
Similar to the previous commit, if we suspend with a delay, and
something in the return path has a pending update, we should abort
the current render and switch to the update instead.
* Track the next unprocessed level globally
Instead of backtracking the return path. The main advantage over the
backtracking approach is that we don't have to backtrack from the source
fiber. (The main disadvantages are that it requires another module-level
variable, and that it could include updates from unrelated
sibling paths.)
* Re-arrange slightly to prevent refactor hazard
It should not be possible to perform any work on a root without
calling `ensureRootIsScheduled` before exiting. Otherwise, we could
fail to schedule a callback for pending work and the app could freeze.
To help prevent a future refactor from introducing such a bug, this
change makes it so that `renderRoot` is always wrapped in try-finally,
and the `finally` block calls `ensureRootIsScheduled`.
* Remove recursive calls to `renderRoot`.
There are a few leftover cases where `renderRoot` is called recursively.
All of them are related to synchronously flushing work before its
expiration time.
We can remove these calls by tracking the last expired level on the
root, similar to what we do for other types of pending work, like pings.
* Remove argument from performSyncWorkOnRoot
Read the expiration time from the root, like we do
in performConcurrentWorkOnRoot.
This happens for example when a deleted boundary transfers its pending
promises to the list so that the list can be retried.
This wasn't caught by unit tests because this flag wasn't on in those
tests.
* Fix DevTools new prop input size
* Don't allow adding new values unless an overridePropsFn function has been provided.
* Do not show empty 'none' label ablve a new prop input
* Extracted sanitizeForParse
* Added canAddEntries flag to InspectedElementTree
* Added EditableKey component.
* Added support to add an additional entry.
* Added support to add more complex data structures in the EditableValue component. Added support to change the dataType of the value that is being changed.
* Fixed flow error.
* Removed unneeded fragment.
* Renamed EditableKey -> EditableName
* Removed unneeded dependency
* Removed problematic props to state hook.
* Prettified changes.
* Removed unused import.
* Fixed shouldStringify check.
* Removed testing props from EditableProps.
* Made some inline tweaks
* Correct link for troubleshooting react-dev-tools (#16690)
As pointed out in #16690 - the link for 'React Tab Doesn't Show Up' points to the empty README.MD.
This points it to that section in the v3 version README.MD - until an updated section will be added to the new dev-tools.
* Add a "The React Tab Doesn't Show Up" section
Add the troubleshooting section to the react dev tools readme
* point to the correct section in react-dev-tools readme
After adding the troubleshooting section to the readme - this will point to the correct place
* Moved README file to GitHub
* Update new issue link to include DevTools label
If we find a Container that might mean that we're on a node that is inside
a Suspense boundary that is directly inside the Container root.
Imagine the div is a Container and the span is a dehydrated instance:
```
<div>
<!--$-->
<span />
<!--/$-->
</div>
```
There's no way to tests this yet since I'm not actually utilizing
the return value yet.
The solution is to just use the same path to check for a Suspense boundary
as if we find a parent instance.
* Don't invoke listeners on parent of dehydrated event target
* Move Suspense boundary check to getClosestInstanceFromNode
Now getClosestInstanceFromNode can return either a host component,
host text component or suspense component when the suspense
component is dehydrated.
We then use that to ignore events on a suspense component.
* Attach the HostRoot fiber to the DOM container
This lets us detect if an event happens on this root's subtree before it
has rendered something.
* Add todo
The approach of checking isFiberMounted answers if we might be in an
in-progress hydration but it doesn't answer which root or boundary
might be in-progress so we don't know what to wait for.
This needs some refactoring.
* Refactor isFiberMountedImpl to getNearestMountedFiber
We'll need the nearest boundary for event replaying so this prepares for
that.
This surfaced an issue that we attach Hydrating tag on the root but normally
this (and Placement) is attached on the child. This surfaced an issue
that this can lead to both Placement and Hydrating effects which is not
supported so we need to ensure that we only ever use one or the other.
* Add todo for bug I spotted
* Cache tags
* Check the ContainerInstanceKey before the InstanceKey
The container is inside the instance, so we must find it before the
instance, since otherwise we'll miss it.
This is a partial replacement for the 'Press' responder:
1. `useTap` is scoped to pointers (no keyboard support). Our current thinking is
that "responders" should be limited to working with pointers, and that they can
be combined with 'useKeyboard' in user-space. For example, we might create a
'usePress' hook in user-space that combines 'useTap' with 'useKeyboard' to react
to both pointers and keyboard interactions.
2. `useTap` cancels the gesture once the pointer moves over an element that is
not within the responder target's subtree. This differs from `usePress` (and
React Native), where the gesture remains active after the pointer exits the
target's subtree and is restarted once the pointer reenters. One of the
drawbacks with the `usePress` behavior is that it requires repeatedly measuring
DOM elements (which can cause jank) to perform hit region tests. `useTap` avoids
doing this and relies on `document.elementFromPoint` only to support the
TouchEvent fallbacks.
3. `useTap` calls `onTapUpdate` when the active gesture's state changes,
`onTapEnd` when the gesture successfully completes. and `onTapCancel` when it
fails. There is no `onTap` callback. `usePress` did not explicitly report back
when the gesture failed, and product developers were confused about the
difference between `onPress` and `onPressEnd`.
4. `useTap` explicitly separates the PointerEvent implementation from the
MouseEvent/TouchEvent fallback.
5. `useTap` has better unit test coverage . All pointer types and the fallback
environment are tested. The shape of the gesture state object is also defined
and tested.
* Added anchor dom element in order to successfully download profiling data.
* Reworked downloadFile to accept a DOMElement in order for FF to successfully download profiling data.
* Prettify downloadFile changes.
In order to foster healthy open source communities, we're adopting the
[Contributor Covenant](https://www.contributor-covenant.org/). It has been
built by open source community members and represents a shared understanding of
what is expected from a healthy community.
This babel transform is a fork of the @babel/plugin-transform-react-jsx transform and is for experimentation purposes only. We don't plan to own this code in the future, and we will upstream this to Babel at some point once we've proven out the concept.
As per the RFC to simplify element creation, we want to change the JSX transform from targeting React.createElement(type, props, children) to React.jsx(type, props, key). This modifies the existing @babel/plugin-transform-react-jsx (and helper) babel plugin to support React.jsx and React.jsxDEV.
The main differences between React.jsx/React.jsxDEV and React.createElement are:
1.) key is now passed as an explicit argument rather than through props
3.) children are now passed through props rather than as an explicit argument
4.) props must always be an object
5.) __source and and __self are now passed as separate arguments into React.jsxDEV rather than through props
Part of the rationale for this change is that we want to deprecate key spread through props because this is an expensive dynamic comparison operation. We want users instead always explicitly pass key as a prop. However, in the interim, we need a way to distinguish between <div {...props} key={foo} /> and <div key={foo} {...props} />. Therefore, until we completely deprecate key spreading, we will use React.createElement to transform <div {...props} key="Hi" /> and React.jsx to transform everything else.
* Revert "Revert "[Scheduler] Profiling features (#16145)" (#16392)"
This reverts commit 4ba1412305.
* Fix copy paste mistake
* Remove init path dependency on ArrayBuffer
* Add a regression test for cancelling multiple tasks
* Prevent deopt from adding isQueued later
* Remove pop() calls that were added for profiling
* Verify that Suspend/Unsuspend events match up in tests
This currently breaks tests.
* Treat Suspend and Resume as exiting and entering work loop
Their definitions used to be more fuzzy. For example, Suspend didn't always fire on exit, and sometimes fired when we did _not_ exit (such as at task enqueue).
I chatted to Boone, and he's saying treating Suspend and Resume as strictly exiting and entering the loop is fine for their use case.
* Revert "Prevent deopt from adding isQueued later"
This reverts commit 9c30b0b695d81e9c43b296ab93d895e4416ef713.
Unnecessary because GCC
* Start counter with 1
* Group exports into unstable_Profiling namespace
* No catch in PROD codepath
* No label TODO
* No null checks
* Refactor a bit to use less property access
* Add test for invoking an event before mount
* Add Hydration effect tag
This is equivalent to a "Placement" effect in that it's a new insertion
to the tree but it doesn't need an actual mutation.
It is only used to determine if a subtree has actually mounted yet.
* Use the Hydration flag for Roots
Previous roots had a Placement flag on them as a hack for this case but
since we have a special flag for it now, we can just use that.
* Add Flare test
The semantics of 'button' on events differs between PointerEvent and
MouseEvent, whereas they are the same for 'buttons'. Furthermore, 'buttons'
allows developers to determine when multiple buttons are pressed as the same
time.
https://w3c.github.io/pointerevents/#the-button-property
* Add a way to skip/only tests to RulesOfHooks test
* [ESLint] Forbid top-level use*() calls
* Add a regression test for logical expressions
This is not a change. Just adding more coverage.
This patch formalizes the mock native events and event sequences used in unit tests.
The `createEventTarget` function returns an object that can be used to dispatch native event sequences on the target without having to manually do so across all the scenarios we need to account for. Unit tests can be written as if we were only working with PointerEvent, but they will dispatch realistic native event sequences based on the execution environment (e.g., is PointerEvent supported?) and pointer type.
```
describe.each(environments)('Suite', (hasPointerEvents) => {
beforeEach(() => {
// setup
});
test.each(pointerTypes)('Test', (pointerType) => {
const target = createEventTarget(node);
target.pointerdown({pointerType});
expect(callback).toBeCalled();
});
});
```
Every native event that is dispatched now includes a complete object by default. The properties of the events can be customized. Properties that shouldn't be relied on in responder implementations are excluded from the mock native events to ensure tests will fail. Equivalent properties are normalized across different event types, e.g., 'pointerId' is converted to 'identifier' before a TouchEvent is dispatched.
1. Run the tests in both an environment without PointerEvent and one with PointerEvent.
2. Improve test coverage to include both mouse and touch pointers.
3. Change 'Press' so that it only listens to either pointer events or fallbacks events.
* Fixed issue with def being undefined while referencing arguments.
* Removed todo comment.
* Skip exhaustive deps check if def is null.
* Fixed code formatting in ExhaustiveDeps.
* Removed unneeded comment in ExhaustiveDeps.
* [Scheduler] Mark user-timing events
Marks when Scheduler starts and stops running a task. Also marks when
a task is initially scheduled, and when Scheduler is waiting for a
callback, which can't be inferred from a sample-based JavaScript CPU
profile alone.
The plan is to use the user-timing events to build a Scheduler profiler
that shows how the lifetime of tasks interact with each other and
with unscheduled main thread work.
The test suite works by printing an text representation of a
Scheduler flamegraph.
* Expose shared array buffer with profiling info
Array contains
- the priority Scheduler is currently running
- the size of the queue
- the id of the currently running task
* Replace user-timing calls with event log
Events are written to an array buffer using a custom instruction format.
For now, this is only meant to be used during page start up, before the
profiler worker has a chance to start up. Once the worker is ready, call
`stopLoggingProfilerEvents` to return the log up to that point, then
send the array buffer to the worker.
Then switch to the sampling based approach.
* Record the current run ID
Each synchronous block of Scheduler work is given a unique run ID. This
is different than a task ID because a single task will have more than
one run if it yields with a continuation.
Provides partial support for React.lazy() components from the existing PartialRenderer server-side renderer.
Lazy components which are already resolved (or rejected), perhaps with something like `react-ssr-prepass`, can be continued into synchronously. If they have not yet been initialized, they'll be initialized before checking, opening the possibility to exploit this capability with a babel transform. If they're pending (which will typically be the case for a just initialized async ctor) then the existing invariant continues to be thrown.
* Test that we can suspend updates while waiting to hydrate
* Attempt hydration at a higher pri first if props/context changes
* Retrying a dehydrated boundary pings at the earliest forced time
This might quickly become an already expired time.
* Mark the render as delayed if we have to retry
This allows the suspense config to kick in and we can wait for much longer
before we're forced to give up on hydrating.
If we get an insertion after a boundary, that has not yet been hydrated,
we take our best guess at which state the HTML is showing.
isSuspenseInstancePending means that we're still waiting for more server
HTML before we can hydrate. This should mean that we're showing the
fallback state.
isSuspenseInstanceFallback means that we want to client render something.
That most likely means that the server was unable to render and is
displaying a fallback state in this slot.
Adds tests to ensure that dehydrated components don't consider the force
flag.
* Move dehydrated to be child of regular SuspenseComponent
We now store the comment node on SuspenseState instead and that indicates
that this SuspenseComponent is still dehydrated.
We also store a child but that is only used to represent the DOM node for
deletions and getNextHostSibling.
* Move logic from DehydratedSuspenseComponent to SuspenseComponent
Forked based on SuspenseState.dehydrated instead.
* Retry logic for dehydrated boundary
We can now simplify the logic for retrying dehydrated boundaries without
hydrating. This is becomes simply a reconciliation against the dehydrated
fragment which gets deleted, and the new children gets inserted.
* Remove dehydrated from throw
Instead we use the regular Suspense path. To save code, we attach retry
listeners in the commit phase even though technically we don't have to.
* Pop to nearest Suspense
I think this is right...?
* Popping hydration state should skip past the dehydrated instance
* Split mount from update and special case suspended second pass
The DidCapture flag isn't used consistently in the same way. We need
further refactor for this.
* Reorganize update path
If we remove the dehydration status in the first pass and then do a second
pass because we suspended, then we need to continue as if it didn't
previously suspend. Since there is no fragment child etc.
However, we must readd the deletion.
* Schedule context work on the boundary and not the child
* Warn for Suspense hydration in legacy mode
It does a two pass render that client renders the content.
* Rename DehydratedSuspenseComponent -> DehydratedFragment
This now doesn't represent a suspense boundary itself. Its parent does.
This Fiber represents the fragment around the dehydrated content.
* Refactor returns
Avoids the temporary mutable variables. I kept losing track of them.
* Add a comment explaining the type.
Placing it in the type since that's the central point as opposed to spread
out.
This is a bad bug. It means that we sometimes inherit
didReceiveUpdate from a previous component's begin.
Effectively this only means that we're overrendering in some cases.
We should refactor to get rid of this as a global flag.
* Disabled (with a follow up TODO) the call in the reload-and-profile toggle.
* Disabled reload-and-profile in Firefox extension for now, since it was triggering a disconnected port error.
* Fixed Safari layout bug that caused profiler charts to be hidden.
Separate the PointerEvent and fallback implementations.
Fix the unit tests to cover both PointerEvent and non-PointerEvent environments.
Fix the focus-visible related callbacks to get called when keys other than "Tab" are used.
@acdlite while browsing Twitter, I saw [an opportunity][1] to do
something more productive than browsing Twitter.
[1]: https://twitter.com/acdlite/status/1160247965908234240
Test plan:
`yarn flow-ci`, `yarn test-prod`, `yarn lint`
This code is being compiled incorrectly by something in the Facebook
build pipeline. I'm removing it temporarily to unblock the sync while
we investigate.
Currently this is getting marked as Never which is the normal continuation
for a dehydrated boundary, but if it is client-rendered it has a higher
priority. That causes us to drop the interaction tracing for that render.
This colocates the marking where we actually set the expiration time.
**Problem**
The existing responders listen to pointer events by default and add fallback events if PointerEvent is not supported. However, this complicates the responders and makes it easy to create a problematic unit test environment. jsdom doesn't support PointerEvent, which means that the responders end up listening to pointer events *and* fallback events in unit tests. This isn't a direct problem in production environments, because no browser will fire pointer events if they aren't supported. But in the unit test environment, we often dispatch event sequences taken from browsers that support pointer events. This means that what we're often testing is actually a (complex) scenario that cannot even occur in production: a responder that is listening to and receives both pointer events and fallback events. Not only does this risk making responders more complicated to implement but it could also hide bugs in implementations.
**Response**
Implement the responders so that they're only listening to *either* pointer events *or* fallback events, never both. This should make the default pointer events implementations significantly simpler and easier to test, as well as free to rely on the complete PointerEvents API. In the future it should also make DCE easier for target environments that are known to support PointerEvents, as we can use build tools with an equivalent of the runtime check. The fallback events (touch and mouse) need to coexist and be resilient to browser emulated events. Our unit tests should express a suite of high-level interactions that can be run in environments with and without PointerEvents support.
These were discovered by @SimenB in https://github.com/facebook/react/pull/16332. We weren't making actual assertions on some values. This PR makes the assertions, and fixes the tests.
In a previous version of act(), we used a dummy dom element to flush effects. This doesn't need to exist anymore, and this PR removes it. The warning doesn't need to be there either (React will fire a wrong renderer act warning if needed).
When React detects a deprectated/unsafe lifecycle method, the warning points to a page with more details on the why/what of the warning. However, the actual link (https://fb.me/react-async-component-lifecycle-hooks) uses the phrase "lifecycle-hooks" which is confusing since it doesn't have anything to do with hooks. This PR changes the link to something less confusing - https://fb.me/react-unsafe-component-lifecycles.
Upgraded from Babel 6 to Babel 7.
The only significant change seems to be the way `@babel/plugin-transform-classes` handles classes differently from `babel-plugin-transform-es2015-classes`. In regular mode, the former injects a `_createClass` function that increases the bundle size, and in the latter it removes the safeguard checks. However, this is okay because we don't all classes in new features, and we want to deprecate class usage in the future in the react repo.
Co-authored-by: Luna Ruan <luna@fb.com>
Co-authored-by: Abdul Rauf <abdulraufmujahid@gmail.com>
Co-authored-by: Maksim Markelov <maks-markel@mail.ru>
* [Scheduler] Store Tasks on a Min Binary Heap
Switches Scheduler's priority queue implementation (for both tasks and
timers) to an array-based min binary heap.
This replaces the naive linked-list implementation that was left over
from the queue we once used to schedule React roots. A list was arguably
fine when it was only used for roots, since the total number of roots is
usually small, and is only 1 in the common case of a single-page app.
Since Scheduler is now used for many types of JavaScript tasks (e.g.
including timers), the total number of tasks can be much larger.
Binary heaps are the standard way to implement priority queues.
Insertion is O(1) in the average case (append to the end) and O(log n)
in the worst. Deletion is O(log n). Peek is O(1).
* Sophie nits
We might reenter a hydration state, when attempting to hydrate a boundary.
We need to ensure that we reset it to not hydrating once we exit it.
Otherwise the next sibling will still be in hydration mode.
This happens in this case: `<!--$!--><!--$!-->...<!--/$--><!--/$-->...`
getNextHydratableInstanceAfterSuspenseInstance didn't take
SUSPENSE_FALLBACK_START_DATA or SUSPENSE_PENDING_START_DATA into account
so if a boundary was in one of those states, it wouldn't be considered to
push the stack of boundaries. As a result the first end comment was
considered the end but it really should've been the second end comment.
The next comment then would've been considered something that can be
skipped. However, since the logic in there considered all comments as
"hydratable", it was considered a hydratable node. Since it was considered
a node that didn't actually correspond to anything in the React tree it got
deleted.
The HTML is now `<!--$!--><!--$!-->...<!--/$-->...` and the trailing
content is now hydrated since it did match something.
Next, since this was client rendered, we're going to delete the suspended
boundary by calling clearSuspenseBoundary and then inserting new content.
However, clearSuspenseBoundary *is* aware of SUSPENSE_FALLBACK_START_DATA
and assumes that there must be another `<!--/$-->` after the first one.
As a result it deleted the trailing content from the DOM since it should
be part of the boundary. However, those DOM nodes were already hydrated in
the React tree. So we end up in an inconsistent state.
When we then try to insert the new content we throw as a result.
I think we would have recovered correctly if clearSuspenseBoundary and
getNextHydratableInstanceAfterSuspenseInstance had the *same* bug but
because they were inconsistent we ended up in a bad place.
We have behaviour divergence for act() between prod and dev (specifically, act() + concurrent mode does not flush fallbacks in prod. This doesn't affect anyone in OSS yet)
We also don't have a good story for writing tests in prod (and what from what I gather, nobody really writes tests in prod mode).
We could have wiped out act() in prod builds, except that _we_ ourselves use act() for our tests when we run them in prod mode.
This PR is a compromise to all of this. We will log a warning if you try to use act() in prod mode, and we silence it in our test suites.
When React schedules a rendering task, it passes a `timeout` option
based on its expiration time. This is intended to avoid starvation
by other React updates. However, it also affects the relative priority
of React tasks and other Scheduler tasks at the same level, like
data processing.
This adds a feature flag to disable passing a `timeout` option to
Scheduler. React tasks will always append themselves to the end of
the queue, without jumping ahead of already scheduled tasks.
This does not affect the order in which React updates within a single
root are processed, but it could affect updates across multiple roots.
This also doesn't remove the expiration from Scheduler. It only means
that React tasks are not given special treatment.
Previously, the suspense priority warning was fired even if the Root wasn't suspended. Changed the warning to fire only when the root is suspended.
Also refactored the suspense priority warning so it's easier to read.
The clean-up function of a passive effect (`useEffect`) usually fires
in a post-commit task, after the browser has painted. However, there is
an exception when the component (or its parent) is deleted from the
tree. In that case, we fire the clean-up function during the
synchronous commit phase, the same phase we use for layout effects.
This is a concession to implementation complexity. Calling it in the
passive effect phase would require either traversing the children of the
deleted fiber again, or including unmount effects as part of the fiber
effect list.
Because the functions are called during the sync phase in this case,
the Scheduler priority is Immediate (the one used for layout) instead
of Normal. We may want to reconsider this trade off later.
If there are adjacent updates we bail out of rendering the suspense list
at all but we may still complete the node. We need to reset the render
state in that case.
I restructured so that this is in the same code path so we don't forget it
in the future.
* Add a feature flag to disable legacy context
* Address review
- invariant -> warning
- Make this.context and context argument actually undefined
* Increase test coverage for lifecycles
* Also disable it on the server is flag is on
* Make this.context {} when disabled, but function context is undefined
* Move checks inside
This wasn't reliable because of browser extension API limitations and required serious throttling to avoid harming performance, so I've decided to just remove it entirely for now.
This dialog is shown in the browser extension the first time a user views v4. It is off by default for the standalone extension, but can be enabled via a public API.
* [act] Wrap IsThisRendererActing in DEV check
So that it doesn't leak into the production bundle. Follow-up to #16240.
* Disable Suspense fallback test in prod
* Bugfix: Priority when effects are flushed early
The priority of passive effects is supposed to be the same as the
priority of the render. This fixes a bug where the priority is sometimes
wrong if the effects are flushed early.
But the priority should really never be higher than Normal Priority.
I'll change that in the next commit.
* Effects never have higher than normal priority
Effects currently have the same priority as the render that spawns them.
This changes the behavior so that effects always have normal priority,
or lower if the render priority is lower (e.g. offscreen prerendering).
The implementation is a bit awkward because of the way `renderRoot`,
`commitRoot`, and `flushPassiveEffects` are split. This is a known
factoring problem that I'm planning to address once 16.9 is released.
In this PR, for tests (specifically, code inside an `act()` scope), we immediately trigger work that would have otherwise required a timeout. This makes it simpler to tests loading/spinner states, and makes tests resilient to changes in React.
For some of our tests(specifically, ReactSuspenseWithNoopRenderer-test.internal), we _don't_ want fallbacks to immediately trigger, because we're testing intermediate states and such. Added a feature flag `flushSuspenseFallbacksInTests` to disable this behaviour on a per case basis.
Concurrent/Batched mode tests should always be run with a mocked scheduler (v17 or not). This PR adds a warning for the same. I'll put up a separate PR to the docs with a page detailing how to mock the scheduler.
This change adds support for element inspecting within `<iframe/>`s.
The iframes are kept in a Set so that we only append listeners once and
clean them up properly. I’ve run a few tests and it seems to behave as
expected.
The fixture includes a cross-origin iframe to make sure we do not error
in this case.
1. Compare element indices rather than ids (since these don't necessarily correlate)
2. Restored previous behaior when new search text reduces the number of results past the currently-selected element.
Merge PR #353 from @fanny
This change changes search beahvior to initially select the result nearest the currently selected element (rather than selecting the first result in the set).
Adds experimental flag to yield many times per frame using a message
event loop, instead of the current approach of guessing the next vsync
and yielding at the end of the frame.
This new approach forgoes a `requestAnimationFrame` entirely. It posts a
message event and performs a small amount of work (5ms) before yielding
to the browser, regardless of where it might be in the vsync cycle. At
the end of the event, if there's work left over, it posts another
message event.
This should keep the main thread responsive even for really high frame
rates. It also shouldn't matter if the hardware frame rate changes after
page load (our current heuristic only detects if the frame rate
increases, not decreases).
The main risk is that yielding more often will exacerbate main thread
contention with other browser tasks.
Let's try it and see.
CSS source maps require the style-loader to use URL.createObjectURL (rather than just a <style> tag). For some reason, this crashes Electron's webview process, which completely breaks the embedded extension inside of Nuclide and other Electron apps. This commit turns (CSS) source maps off for production builds to avoid this crash.
* Do not hyphenate custom CSS property
* Move check into the processStyleName fn
* Formatting
* add test
* Put isCustomProperty check after conditional return
* add test to `ReactDOMServerIntegration` and supress warning
* Don't indexOf twice
* Simpler fix
Not returning the value of flushPassiveEffects() in flushWork() meant that with async act, we wouldn't flush all work with cascading effects. This PR fixes that oversight, and adds some tests to catch this in the future.
The Scheduler implementation uses browser APIs like `MessageChannel`,
`requestAnimationFrame`, and `setTimeout` to schedule work on the main
thread. Most of our tests treat these as implementation details;
however, the sequence and timing of these APIs are not precisely
specified, and can vary wildly across browsers.
To prevent regressions, we need the ability to simulate specific edge
cases that we may encounter in various browsers.
This adds a new test suite that mocks all browser methods used in our
implementation. It assumes as little as possible about the order and
timing of events. The only thing it assumes is that
requestAnimationFrame is passed a frame time that is equal to or less
than the time returned by performance.now. Everything else can be
controlled at will.
It also includes Scheduler-specific invariants, e.g. only one rAF
callback can be scheduled at a time.
It overlaps slightly with the existing SchedulerDOM-test suite, which
also mocks the browser APIs, but exposes a higher-level set of testing
primitives. I will consolidate the two suites in a follow-up.
But only do this if we can verify the element file path. This hopefully avoids the case where clicking the button does nothing because of an invalid/incomplete path.
* Added shadow to modals
* Change default "collapse new nodes" to be disabled rather than enabled
* Changed setting label "Collapse newly added components by default" to "Expand component tree by default"
* Change CSS media query for settings popup to show labels at smaller size
* Hide "Inspect the matching DOM element" button (since it doesnt really serve a purpose in standalone)
* Fixed small size bug for settings icon (viewbox of 20x20 instead of 24x24)
* bugfix: window.addEventListener/window.removeEventListener is not defined in Hermes.
This adds a 'SuspenseCallback' feature flag. When the property is set on
a suspense component it will be called during the commit phase with a
set of the immediate thenable for this component. This will allow user
code to build runtime tracing of the cause for a suspense boundary.
Given this snippet:
```jsx
TestRenderer.act(() => {
TestUtils.act(() => {
TestRenderer.create(<Effecty />);
});
});
```
We want to make sure that all work is only flushed on exiting the outermost act().
Now, naively doing this based on actingScopeDepth would work with a mocked scheduler, where flushAll() would flush all work across renderers.
This doesn't work without mocking the scheduler though; and where flushing work only works per renderer. So we disable this behaviour for a non-mocked scenario. This seems like an ok tradeoff.
Noticed when looking at the performance profiler with Luna that it's
hard to tell which event causes `performWorkUntilDeadline` to fire
because these functions are anonymous.
Always sets `isRAFLoopRunning` back to false when an animation frame is
scheduled. Fixes a bug where two rAFs fire in the same frame, but the
second one exits and fails to schedule a new rAF.
Fixes bug observed in Safari.
Prevents Spacebar from scrolling the window.
Prevents Enter from triggering a navigation if preventDefault is true.
Fixes the emulated mouse events test.
Improved warning whenever lower priority events (ex. data fetching, page load) happen during a high priority update (ex. hover/click events) to include:
1.) Name of component that triggered the high priority update or
2.) Information that the update was triggered on the root
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
* Patch console.warn and console.error to auto-append owners-only component stacks.
This setting is enabled by default and will work for React Native even if no front-end DevTools shell is being used. The setting can be disabled via a new, persisted user preference though.
- 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.
* Add version 4 react-devtools and react-devtools-core packages which support both React Native and e.g. Safari or iframe DOM usage.
* Replaces typed operations arrays with regular arrays in order to support Hermes. This is unfortunate, since in theory a typed array buffer could be more efficiently transferred between frontend and backend for the web extension, but this never actually worked properly in v8, only Spidermonkey, and it fails entirely in Hermes so for the time being- it's been removed.
* Adds support for React Native (paper renderer)
* Adds a style editor for react-native and react-native-web
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
Preemptively update tests wrt 'parser' requiring an absolute
path rather than a package name, even though the project is
still using ESLint 4.
Fixes#15971
* use toWarnDev for dom fixture tests
forks toWarnDev from root into fixture/dom, updates tes tests to use it
* disable act() warnings for react-art()
- For 'secondary' renderers like react-act, we don't want to fire missing act() warnings; the wrapping renderer will fire warnings anyway, and when it flushes, it flushes effects *across* renderers.
- I could have used isPrimaryRenderer as the flag, but this is marked as false for react-test-renderer, and we *do* want the warning to fire for it. Hence a new flag.
* add missing dependency `art` to fixtures/dom
* Retry failed roots on refresh
* Don't prevent retry after error -> render(null) special case
The check wasn't very resilient because in Concurrent Mode it looks like we can get further follow-up commits even if we captured an error. So we can't reliably distinguish the case where after an error you _manually_ rendered null.
Retrying on an edit after a tree failed _and_ you rendered null in the same tree seems fine. It's also very unlikely a pattern like this actually exists in the wild.
* warn if passive effects get queued outside of an act() call
While the code itself isn't much (it adds the warning to mountEffect() and updateEffect() in ReactFiberHooks), it does change a lot of our tests. We follow a bad-ish pattern here, which is doing asserts inside act() scopes, but it makes sense for *us* because we're testing intermediate states, and we're manually flush/yield what we need in these tests.
This commit has one last failing test. Working on it.
* pass lint
* pass failing test, fixes another
- a test was failing in ReactDOMServerIntegrationHooks while testing an effect; the behaviour of yields was different from browser and server when wrapped with act(). further, because of how we initialized modules, act() around renders wasn't working corrrectly. solved by passing in ReactTestUtils in initModules, and checking on the finally yielded values in the specific test.
- in ReactUpdates, while testing an infinite recursion detection, the test needed to be wrapped in an act(), which would have caused the recusrsion error to throw. solived by rethrowing the error from inside the act().
* pass ReactDOMServerSuspense
* stray todo
* a better message, consistent with the state update one.
* [Scheduler] requestPaint
Signals to Scheduler that the browser needs to paint the screen. React
will call it in the commit phase. Scheduler will yield at the end of
the current frame, even if there is no pending input.
When `isInputPending` is not available, this has no effect, because we
yield at the end of every frame regardless.
React will call `requestPaint` in the commit phase as long as there's at
least one effect. We could choose not to call it if none of the effects
are DOM mutations, but this is so rare that it doesn't seem worthwhile
to bother checking.
* Fall back gracefully if requestPaint is missing
At the end of each frame, Scheduler yields control of the main thread so
the browser can execute important tasks; most importantly, painting the
screen and responding to user input. There's some overhead involved in
regaining control of the main thread, so we'd like to yield as
infrequently as possible to keep the UI responsive.
The reason we yield on every frame is because there's no way for us to
know whether we're blocking user input.
`isInputPending` is an experimental browser API that gives us this
information. It tells us whether there's a pending user input, which
also means it tells us if there's *not* a pending user input. We can use
this signal to decide whether it's OK not to yield.
There's a max frame length after which we'll yield regardless, as a
precaution against blocking non-input tasks that we don't know about.
* Expire rendering the tail of SuspenseList after a timeout
This is the first Suspense feature that isn't actually dependent on IO.
The thinking here is that it's normal for a SuspenseList to show loading
states, and it'll be designed to handle it one at a time.
However, sometimes there are lists with really big items that take a long
time to CPU render. Since data can become available as we do that, it is
likely that we have all the data and become CPU bound.
In that case, the list would naively just render until the end and then
display all items at once. I think that's actually what you want for fast
lists. However, for slow ones (like News Feed), you're better off showing
a few rows at a time.
It's not necessarily one at a time because if you can do many in a short
period of time and fit them all on the screen, then it's better to do them
all at once than pop them in one at a time very quickly.
Therefore, I use a heuristic of trying to render as many rows as I can in
500ms before giving up.
This timer starts before the first row of the tail and we only check it
after. This ensures that we always make a little progress each attempt.
An alternative approach could be to start the time before doing the head
of the list but we don't want that being slow prevent us from making
further progress.
Currently, I disable this optimization at Never priority because there's
nothing intermediate that becomes visible anyway.
* Fix tracing through a SuspenseList
This ensures that we can spawn new work during render through arbitrary
priorities.
We'll need this for other features too.
Since each priority can commit separately we need to use an array to
include the current interactions on each priority.
The responder region calculation logic wasn't updating the deactivation region
during the lifetime of an event instance, causing incorrect behaviour when the
current press ends outside the press target and if the press target has moved
since the last time the first-and-only time the deactivation region was
measured.
* Add forwards option
* Add backwards option
* Add comment
* Add customized warning messages for case and typos
* Add some more tests for insertions and updates in start/middle/end
* reset scope depth on synchronous errors
we weren't resetting the acting scope depth on sync errors thrown in the callback. this fixes that.
* typos
* add a test to make sure sync error propagate
* Add SuspenseList component type
* Push SuspenseContext for SuspenseList
* Force Suspense boundaries into their fallback state
In the "together" mode, we do a second render pass that forces the
fallbacks to stay in place, if not all can unsuspend at once.
* Add test
* Transfer thennables to the SuspenseList
This way, we end up retrying the SuspenseList in case the nested boundary
that just suspended doesn't actually get mounted with this set of
thennables. This happens when the second pass renders the fallback
directly without first attempting to render the content.
* Add warning for unsupported displayOrder
* Add tests for nested sibling boundaries and nested lists
* Fix nested SuspenseList forwarding thennables
* Rename displayOrder to revealOrder
Display order has some "display list" connotations making it sound like
a z-index thing.
Reveal indicates that this isn't really about when something gets rendered
or is ready to be rendered. It's about when content that is already there
gets to be revealed.
* Add test for avoided boundaries
* Make SuspenseList a noop in legacy mode
* Use an explicit suspense list state object
This will be used for more things in the directional case.
* Track mounted roots via DevTools Hook
* Add helper utilities to the runtime
These utilities will likely be needed by all module systems, so let's just put them here.
* Wrap more things in __DEV__
* Fix tests to also be DEV-only
Adds a `delay` option to `scheduleCallback`. When specified, the task is
not scheduled until after the delay has elapsed.
Delayed tasks are scheduled on a timer queue maintained by Scheduler,
instead of directly with the browser. The main benefit is to reduce the
number of native browser timers that Scheduler's `message` event handler
has to contend with; so, after yielding to the browser at the end of the
frame, Scheduler will more quickly regain control of the main thread.
Because we're able to flush the timer queue without yielding to browser
timer events, there's also less task switching overhead (though in the
absence of `isInputPending`, this is mostly a theoretical win since we
yield every frame regardless).
If the queue of non-delayed tasks is non-empty — that is, if there is
pending CPU bound work — Scheduler is able to avoid a browser timer
entirely by periodically checking its own timer queue while flushing
tasks (inside the `message` event handler). Once the CPU-bound work is
complete, if there are still pending delayed tasks, Scheduler will
schedule a single browser timer that fires once the earliest delay
has elapsed.
* [scheduler] Internal rename: Callback -> Task
Rename Callback type to Task. Does not affect the public API, only
internal names, though eventually we'll probably want to align with the
WICG Main-thread Scheduling proposal
(https://github.com/WICG/main-thread-scheduling).
* [scheduler] flushFirstTask() -> flushTask(task)
Pass task as an argument to `flushTask` instead of using a module-
level variable.
* [scheduler] Add startTime field
This does not change any semantics, but in the future `startTime` may
represent a future time, to support delayed tasks.
* [Scheduler] Use continuation pattern for host cb
As I prepare to implement integrated timers, I noticed some
peculiarities in the Scheduler implementation that could afford to be
cleaned up.
This is a refactor and shouldn't affect any observable behavior; mostly
it removes some concepts that existed in earlier iterations of Scheduler
and are no longer needed.
The main change is to how the DOM implementation schedules an additional
callback before yielding to the main thread. It used to follow the same
code path for scheduling task; now it has its own branch directly
inside the message event handler. The special case for error handling
— where we call `postMessage` immediately without waiting for rAF —
has similarly been localized inside the catch block of the message
event handler.
* Rename `disableContextMenu` to `preventContextMenu`
* Change the behaviour of `preventContextMenu` so that `onContextMenu` is still called when the native context menu is prevented.
* Run Fresh tests in two modes: with and without destructuring
Destructuring transform messes up the way we collect signatures for Hooks. This adds failing tests.
* Extract collecting calls to Hooks into a separate visitor
This introduces a bit of a perf penalty but makes our plugin resilient to presence of destructuring transform and their order. Fixes new tests.
* Inline some logic into the call visitor
Follow up to #15861.
Turns out you can't set `!important` using a normal property assignment.
You have to use `style.setProperty`.
Maybe Andrew *should* just learn CSS.
IE9 doesn't support `style.setProperty` so we'll fall back to setting
`display: none` without `important`, like we did before #15861 Our
advice for apps that need to support IE9 will be to avoid using
`!important`. Which seems like good advice in general, but IANACSSE.
Tested on FB and using our Suspense DOM fixture.
Suspended nodes are hidden using an inline `display: none` style. We do
this instead of removing the nodes from the DOM so that their state is
preserved when they are shown again.
Inline styles have the greatest specificity, but they are superseded by
`!important`. To prevent an external style from overriding React's, this
commit changes the hidden style to `display: none !important`.
MaYBE AnDREw sHOulD JusT LEArn Css
I attempted to write a unit test using `getComputedStyle` but JSDOM
doesn't respect `!important`. I think our existing tests are sufficient
but if we were to decide we need something more robust, I would set up
an e2e test.
* Fix existing test
This test included a change in variable name. It wasn't needed, and distracts from the actual thing being tested (the annotation).
* Reset state on edits to initial state argument
* Add a way to check whether there are hot updates
prepareUpdate() now returns null if there are none.
* Add a way to query host nodes for families
* Split the signature call into two calls
This adds a render-time signature call by making __signature__ curried. We need both calls. The init time tells us which type has which signature. The render time call says when's a good time to capture the lazy Hooks tree. This is necessary for supporting inline requires. I will do that in next commit.
* Lazily compute Hook list on first render
This ensures inline requires don't break comparisons between Hook signatures of previous and next versions by caching Hook list at the time of first render.
* Refactor computing Hook signature keys
Instead of a traversal during the comparison, explicitly compute full keys. This makes it easier to debug mismatches.
* Remount classes during hot reload
* Fix a crash when Hook isn't in scope inside the signature
* Minor tweaks
* Support a comment annotation to force state reset
* Refactoring: pass a function instead of WeakMap
This hides the implementation a little bit and reduces how much React knows about the underlying mechanism.
* Refactor: use forceReset to remount unknown Hooks
We already have the logic to reset a component, so let's just reuse it instead of that special case.
* Same as previous commit, but for Flare
I don't know what the public API for setting the event priority should
be. Right now it accepts a numeric enum, but is this what we want?
Maybe it should be a string enum? I've punted on this for now.
* Add test for hover events
* [Events] Add EventPriority enum
React DOM's DispatchConfig for synthetic events has an `isDiscrete`
field that affects how updates triggered by an event are scheduled.
Events are either discrete or continuous.
This commit adds an additional type of configuration where an event
has user-blocking priority, but is not discrete. E.g. updates triggered
by hover are more important than the default, but they don't need to
be processed serially. Because there are now three types of event
priority instead of two, I've replaced the `isDiscrete` boolean with an
enum: `eventPriority`.
This commit implements the new enum value but does not change any
behavior. I'll enable it behind a feature flag in the next commit.
I've only implemented this in the legacy event system. I'll leave Flare
for a follow-up.
* enableUserBlockingEvents feature flag
Adds a feature flag to increase the priority of events like `mouseover`,
without making them discrete.
As a result, paddings and sizes (e.g. tab bar heights) will also be impacted now by this preference. More importantly, Profile charts will also use the line height preference, so the 'comfortable' setting will hopefully make profiling data easier to read.
Compare the viewport-relative coordinates of getBoundingClientRect with those
of the event's client{X,Y} values. This fixes press within scrollable nodes.
1. Bugfix: Hide tree grouping/background coloring when inside of collapsed subtree.
2. Bugfix: Don't measure and udpate indentation when Components tab is hidden.
3. Tweak: Lower background color for selected subtree in light theme to increase contrast for text.
4. Tweak: Remove FB-specific displayName check/hack since we will address that by modifying the internal require JS transform.
This commit is a follow-up to https://github.com/facebook/react/pull/15604, which explains more of the rationale behind moving React Native to path-based imports and the work needed in the React repository. In that linked PR, the generated renderers were updated but not the shims; this commit updates the shims.
The problem is that FB needs a different copy of the built renderers than the OSS versions so we need a way for FB code to import different modules than in OSS. This was previously done with Haste, but with the removal of Haste from RN, we need another mechanism. Talking with cpojer, we are using a `.fb.js` extension that Metro can be configured to prioritize over `.js`.
This commit generates FB's renderers with the `.fb.js` extension and OSS renderers with just `.js`. This way, FB can internally configure Metro to use the `.fb.js` implementations and OSS will use the `.js` ones, letting us swap out which implementation gets bundled.
Test Plan: Generated the renderers and shims with `yarn build` and then verified that the generated shims don't contain any Haste-style imports. Copied the renderers and shims into RN manually and launched the RNTester app to verify it loads end-to-end. Added `.fb.js` to the extensions in `metro.config.js` and verified that the FB-specific bundles loaded.
This is important since we are caching element sizes by DOM (in a WeakMap). Toggling (as well as insertion/deletion) might otherwise break this in some cases.
Remove selected guideline in favor of background color for selected subtree.
Add badges in grid format to selected elements prop panel.
Show badges beside owners list.
If an event in the old system is dispatched synchronously within an
event from the new system, or vice versa, and the inner event is a
discrete update, React should not flush pending discrete updates before
firing the inner event's handlers, even if the outer event is not
discrete.
Another way of saying this is that nested events should never force
React to flush discrete updates.
Arguably, if the outer event is not a discrete event, then the inner
event _should_ flush the pending events. However, that would be a
breaking change. I would argue this isn't so bad, however, given that
nested events are pretty rare. They don't fit nicely into our event
model regardless, since we don't support nested React renders. In the
future we should consider warning when events are nested.
WorkPhase is an enum that represents the currently executing phase of
the React update -> render -> commit cycle. However, in practice, it's
hard to use because different "phases" can be nested inside each other.
For example, the commit phase can be nested inside the
"batched phase."
This replaces WorkPhase with a different concept: ExecutionContext.
ExecutionContext is a bitmask instead of an enum. It represents a stack
of React entry points. For example, when `batchedUpdates` is called
from inside an effect, the ExecutionContext is
`BatchedContext | CommitContext`.
* Fix issue with Tab+alt not being considered as isGlobalFocusVisible candidate on Mac
* Add test for Tab+alt on Mac setting pointerType: "keyboard" on a focus event
* Track most recent commit time of a fallback globally
This value is going to be used to avoid committing too many fallback
states in quick succession. It doesn't really matter where in the tree
that happened.
This means that we now don't really need the concept of SuspenseState
other than has a flag. It could be made cheaper/simpler.
* Change suspense heuristic
This now eagerly commits non-delayed suspended trees, unless they're
only retries in which case they're throttled to 500ms.
* Restart early if we're going to suspend later
* Use the local variable where appropriate
* Make ReactLazy tests less specific on asserting intermediate states
They're not testing the exact states of the suspense boundaries, only
the result. I keep assertions that they're not already resolved early.
* Adjust Profiler tests to the new heuristics
* Update snapshot tests for user timing tests
I also added a blank initial render to ensuree that we cover the suspended
case.
* Adjust Suspense tests to account for new heuristics
Mostly this just means render the Suspense boundary first so that it
becomes an update instead of initial mount.
* Track whether we have a ping on the currently rendering level
If we get a ping on this level but have not yet suspended, we might
still suspend later. In that case we should still restart.
* Add comment about moving markers
We should add this to throwException so we get these markers earlier.
I've had to rewrite tests that test restarting to account for the delayed
restarting heuristic.
Ideally, we should also be able to restart from within throwException if
we're already ready to restart. Right now we wait until the next yield.
* Add test for restarting during throttled retry
* Add test that we don't restart for initial render
* Add Suspense Heuristics as a comment in Throw
The previous naming scheme used the name of the resulting bundle file.
However, there are cases where multiple bundles have the same filename.
This meant whichever bundle finishes last overwrites the previous ones
with the same name.
The updated naming scheme is `bundle-sizes-<CI_NODE_INDEX>.json`.
Instead of generating a separate info file per bundle, it now creates
one per process.
* warn when using the wrong renderer's act around another renderer's updates
like it says. it uses a real object as the sigil (instead of just a boolean). specifically, it uses a renderer's flushPassiveEffects as the sigil. We also run tests for this separate from our main suite (which doesn't allow loading multiple renderers in a suite), but makes sure to run this in CI as well.
* unneeded (and wrong) comment
* run the dom fixture on CI
* update the sigil only in __DEV__
* remove the obnoxious comment
* use an explicit export for the sigil
* Write size info to separate file per bundle
`bundle-sizes.json` contains the combined size information for every
build. This makes it easier to store and process, but it prevents us
from parallelizing the build script, because each process would need to
write to the same file.
So I've updated the Rollup script to output individual files per build.
A downstream CI job consolidates them into a single file.
I have not parallelized the Rollup script yet. I'll do that next.
* Parallelize the build script
Uses CircleCI's `parallelism` config option to spin up multiple build
processes.
Removes `--extract-errors` argument from CI build script command.
Instead, the author is expected to run `yarn extract-errors` locally
or manually edit the error code map.
The lint rule should be sufficient to catch unminified errors, but
as an extra precaution, I added a post-build step that greps the
production bundles. The post-build step works even if someone disables
the lint rule for a specific line or file.
* Lint rule for unminified errors
Add a lint rule that fails if an invariant message is not part of the
error code map.
The goal is to be more disciplined about adding and modifiying
production error codes. Error codes should be consistent across releases
even if their wording changes, for continuity in logs.
Currently, error codes are added to the error code map via an automated
script that runs right before release. The problem with this approach is
that if someone modifies an error message in the source, but neglects to
modify the corresponding message in the error code map, then the message
will be assigned a new error code, instead of reusing the existing one.
Because the error extraction script only runs before a release, people
rarely modify the error code map in practice. By moving the extraction
step to the PR stage, it forces the author to consider whether the
message should be assigned a new error code. It also allows the reviewer
to review the changes.
The trade off is that it requires more effort and context to land new
error messages, or to modify existing ones, particular for new
contributors who are not familiar with our processes.
Since we already expect users to lint their code, I would argue the
additional burden is marginal. Even if they forget to run the lint
command locally, they will get quick feedback from the CI lint job,
which typically finishes within 2-3 minutes.
* Add unreleased error messages to map
* Generate signatures for Hooks
This currently only works one level deep. For custom Hooks, we'll need to add some way to compose signatures.
* Be more resilient to plugin conflicts
This prevents a class of problems where other plugins cause our visitor to re-run.
It's a standard Babel practice, e.g.:
8c7d4b55c9/packages/babel-plugin-transform-react-constant-elements/src/index.js (L85-L86)
* Remove unnecessary stuff from debugging
* Include Foo.useHookName() calls into the signature
* Add an integration test for adding/removing an effect
* Add integration test for changing custom Hook order
* Include custom Hooks into the signatures
* Fix inferred names for function expressions
* Support export default hoc(Foo) when Foo is defined separately
* Add more built-in Hooks
expirationTime has already been checked if it's sync.
timeout can now be longer than 5 seconds when a suspense config is used.
We might want to adjust the heuristics but it's not internally consistent
without this.
1. Removed auto-updates XML (since the feature doens't work for self hosted extensions)
2. Replaced CRX with packed ZIP (since people are having trouble with the CRX, and auto-udpates doesn't work anyway)
Sometimes the status of the `build` job is not in the first page of
the `/statuses` endpoint. The combined `/status` endpoint consolidates
the entries, though, so it always appears there.
* Refactor component search to prepare for deeper traversals
* Register HOCs with intermediate results
* Register components that are used as JSX types
* Add integration test skeleton
The integration test combines testing runtime together with the Babel plugin. It's a bit harder to debug because multiple things can go wrong, but it helps us build confidence that specific scenarios work well.
* Add HOC integration test and fix conflict with JSX transform
* Infer usage from createElement too
This helps us avoid dependency on the plugin order.
* Remove outdated comments
* Wrap tests in __DEV__
* Support export default hoc(...) for anonymous functions
* Fix test indentation
* Fix comment typo
* Use named function for test as this case is more important
* Rename ReactFiberScheduler to ReactFiberWorkLoop
The scheduling part is mostly extracted out to the scheduler package.
What's remaining is mostly around the loop around each section of work.
I name it something with Work in it because it's very related to the
BeginWork, CompleteWork and UnwindWork sections.
* Extract throwException from UnwindWork
Our throwing works more like algebraic effects in that it's a separate
phase where we find a handler and we later unwind.
* [react-native] Use path-based imports instead of Haste for the RN renderer
To move React Native to standard path-based imports instead of Haste, the RN renderer that is generated from the code in this repo needs to use path-based imports as well since the generated code is vendored by RN. This commit makes it so the interface between the generated renderers and RN does not rely on Haste and instead uses a private interface explicitly defined by RN. This inverts control of the abstraction so that RN decides the internals to export rather than React deciding what to import.
On RN's side, a new module named `react-native/Libraries/ReactPrivate/ReactNativePrivateInterface` explicitly exports the modules used by the renderers in this repo. (There is also a private module for InitializeCore so that we can import it just for the side effects.) On React's side, the various renderer modules access RN internals through the explicit private interface.
The Rollup configuration becomes slimmer since the only external package is now `react-native`, and the individual modules are instead listed out in `ReactNativePrivateInterface`.
Task description: https://github.com/facebook/react-native/issues/24770
Sister RN PR (needs to land before this one): https://github.com/facebook/react-native/pull/24782
Test Plan: Ran unit tests and Flow in this repo. Generated the renderers and manually copied them over to the RN repo. Ran the RN tests and launched the RNTester app.
* Access natively defined "nativeFabricUIManager" instead of importing it
Some places in the Fabric renderers access `nativeFabricUIManager` (a natively defined global) instead of importing UIManager. While this is coupling across repos that depends on the timing of events, it is necessary until we have a way to defer top-level imports to run after `nativeFabricUIManager` is defined. So for consistency we use `nativeFabricUIManager` everywhere (see the comment in https://github.com/facebook/react/pull/15604#pullrequestreview-236842223 for more context).
The sizebot scrapes the GitHub `/statuses` endpoint to get the lastest
CircleCI build number for master, in order to fetch the bundle size
info for that build, which are stored as build artifacts. (There's gotta
be a better way to do this, but that's what we have for now.) This
updates the script to match the name of the updated CircleCI job that
generates the bundle sizes.
* Add initial Babel plugin implementation
* Register exported functions
* Fix missing declarations
Always declare them at the bottom and rely on hoisting.
* Remove unused code
* Don't pass filename to tests
I've decided for now that the plugin doesn't need filename, and it will be handled by module runtime integration instead.
* Fix bugs
* Coalesce variable declarations
Updates the CircleCI config to use the workflows features to run jobs in
parallel, instead of the `parallelism` option. This change alone doesn't
improve the overall build time much, since almost all of the total time
is spent running the Rollup script, which runs entirely sequentially.
But it does improve reporting, and should make it easier to add
additional parallel jobs in the future.
* Fix missing return pointer assignment
I found a bug using the fuzz tester that manifested as incorrect
ordering of children in the host tree, but whose root cause was a
missing `return` pointer assignment on a work-in-progress fiber.
Usually return pointers are set during reconciliation
(`reconcileChildFibers`) but this particular assignment happens inside
the custom reconciliation implementation used by Suspense boundaries.
I would not be surprised if there were similar bugs related to incorrect
return pointers. You're supposed to update the return pointer
whenever a work-in-progress fiber is created, but there's nothing in
the contract of the `createFiber` or `createWorkInProgress` function
that implies this. I propose that we update their signatures to accept
the return fiber as an argument. I will do this in a follow-up.
In this commit, I rearranged `updateSuspenseComponent` slightly so that
every call to `createWorkInProgress` or a `createFiber*` function is
immediately followed by a return pointer assignment.
I hardcoded the fuzz test case that surfaced the bug.
* Update all progressed children in list
`progressedPrimaryChild` is a list, not a single fiber. Need to iterate
through every child and update their return pointers.
* Add a stub for React Fresh Babel plugin package
* Move ReactFresh-test into ReactFresh top level directory
* Add a stub for React Fresh Runtime entry point
* Extract Fresh runtime from tests into its entry point
* Don't traverse children when hot reloading needs a remount
If we're gonna remount that tree anyway, there is no use in traversing its children beforehand.
* Add a test verifying hot reload batches updates
Otherwise there is a risk of it being super slow due to cascades.
* Add a minimal failing test for hot reload
* Set up scaffolding for React Fresh
* Consider type family when comparing elementType
Rendering an element with stale type should not cause it to remount.
We only do this for FunctionComponent tag since checking is unnecessary for classes or host components.
* Add support for forwardRef()
Initially I thought I would compare families of inner .render functions.
However, there is a corner case where this can create false positives. Such as when you forwardRef(X) the same X twice. Those are supposed to be distinct. But if we compare .render functions, we wouldn't be able to distinguish them after first reload.
It seems safer to rely on explicit registration for those. This should be easy when forwardRef() call is in the same file, and usually it would be. For cases like HOCs and style.div`...` factories that return forwardRef(), we could have the __register__ helper itself "dig deeper" and register the inner function.
* Show how forwardRef inner identity can be inferred
The __register__ implementation can read the inner identity itself.
* Add missing __DEV__ to tests
* Add support for memo() (without fixing bailouts)
This adds rudimentary support for memo components. However, we don't actually skip bailouts yet, so this is not very useful by itself alone. Tests have TODOs that we need to remove after bailout skipping is done.
* Refactor type comparison for clarity
* Hot update shouldn't re-render ancestor components unnecessarily
My code had a bug where it checked for a wrong thing in a wrong set, leading us to always re-render.
This fixes the checks so that we only schedule updates for things that were actually edited.
* Add test coverage for memo(fn, areEqual)
* Explicitly skip bailouts for hot reloading fibers
This forces even memo() with shallow comparison to re-render on hot update.
* Refactor scheduling update to reduce duplication
* Remove unused variable in test
* Don't check presence in a set while not hot reloading
* Make scheduleHotUpdate() take named arguments
* Don't keep unedited component types in the type => family map
It's unnecessary because if they haven't been edited, there's no special reconciliation logic.
* Add signatures that force remounting
Signatures let us force a remount of a type even if from React's point of view, type is the same.
A type has one current signature. If that signature changes during next hot update, all Fibers with that type should be deleted and remounted.
We do this by mutating elementType scheduling a parent.
This will be handy to force remount of mismatching Hooks, as well as failed error boundaries.
For this to fully work, we'll need to add a way to skip built-in bailouts for all Fiber types. This will be the most invasive and annoying change. I did it for HostRoot in this PR but there's more. I'll add an automated test case that catches the missing bailout bailouts.
* Support forced remounting for all component types
This teaches all parent component types to remount their child if necessary.
It also adds tests for them.
* Remount effects while preserving state for hot reloaded components
This makes sure that changes to *code* always propagate.
It can break components that aren't resilient to useEffect over-firing, but that seems like a good constraint since you might need to add a dependency later anyway, and this helps avoid coding yourself into the corner.
* Add missing __DEV__ blocks to tests
* Fix unused variables in tests
* Remove outdated TODO
* Expose scheduleHotUpdate directly
* Inline isCompatibleType
* Run one check per component for invalidating deps
This also makes the bailouts more targeted--no need to remount useEffect for a parent component of remounted fiber.
* Resolve .type early
This moves resolving to set up the right .type early instead of doing this before render.
A bit more future-proof in case we want to restructure the begin phase later.
ForwardRef is special because its type is a wrapper but it can be hot reloaded by itself.
So we have a special overload for it that reconstucts the wrapper type if needed.
* Add a Suspense todo
* Use current.type !== workInProgress.type for ignoring deps
This gets rid of one of the sets.
* Use workInProgress.type !== current.type check for force re-render
We still use a set for forced remount though.
* Use wip.type !== current.type check in more places
This also disables the remounting tests. They need a separate approach.
* Use a dedicated remount mechanism
* Add a test for offscreen trees
It has a TODO because it seems like offscreen updates are incorrectly applied too soon.
* Enable offscreen test now that it is fixed
* Fix corner cases in the new remounting mechanism
* Remount failed error boundaries on hot reload
* Fix test now that act() flushes
This test is manual so I don't actually want act here.
* Nits
* Add comments
* Add suspendIfNeeded API and a global scope to track it
Adds a "current" suspense config that gets applied to all updates scheduled
during the current scope.
I suspect we might want to add other types of configurations to the "batch"
so I called it the "batch config".
This works across renderers/roots but they won't actually necessarily go
into the same batch.
* Add the suspenseConfig to all updates created during this scope
* Compute expiration time based on the timeout of the suspense config
* Track if there was a processed suspenseConfig this render pass
We'll use this info to suspend a commit for longer when necessary.
* Mark suspended states that should be avoided as a separate flag
This lets us track which renders we want to suspend for a short time vs
a longer time if possible.
* Suspend until the full expiration time if something asked to suspend
* Reenable an old test that we can now repro again
* Suspend the commit even if it is complete if there is a minimum delay
This can be used to implement spinners that don't flicker if the data
and rendering is really fast.
* Default timeoutMs to low pri expiration if not provided
This is a required argument in the type signature but people may not
supply it and this is a user facing object.
* Rename to withSuspenseConfig and drop the default config
This allow opting out of suspending in some nested scope.
A lot of time when you use this function you'll use it with high level
helpers. Those helpers often want to accept some additional configuration
for suspense and if it should suspend at all. The easiest way is to just
have the api accept null or a suspense config and pass it through. However,
then you have to remember that calling suspendIfNeeded has a default.
It gets simpler by just saying tat you can pass the config. You can have
your own default in user space.
* Track the largest suspense config expiration separately
This ensures that if we've scheduled lower pri work that doesn't have a
suspenseConfig, we don't consider its expiration as the timeout.
* Add basic tests for functionality using each update mechanism
* Fix issue when newly created avoided boundary doesn't suspend with delay
* Add test for loading indicator with minLoadingDurationMs option
* s/flushPassiveEffects/unstable_flushWithoutYielding
a first crack at flushing the scheduler manually from inside act(). uses unstable_flushWithoutYielding(). The tests that changed, mostly replaced toFlushAndYield(...) with toHaveYielded(). For some tests that tested the state of the tree before flushing effects (but still after updates), I replaced act() with bacthedUpdates().
* ugh lint
* pass build, flushPassiveEffects returns nothing now
* pass test-fire
* flush all work (not just effects), add a compatibility mode
of note, unstable_flushWithoutYielding now returns a boolean much like flushPassiveEffects
* umd build for scheduler/unstable_mock, pass the fixture with it
* add a comment to Shcduler.umd.js for why we're exporting unstable_flushWithoutYielding
* run testsutilsact tests in both sync/concurrent modes
* augh lint
* use a feature flag for the missing mock scheduler warning
I also tried writing a test for it, but couldn't get the scheduler to unmock. included the failing test.
* Update ReactTestUtilsAct-test.js
- pass the mock scheduler warning test,
- rewrite some tests to use Scheduler.yieldValue
- structure concurrent/legacy suites neatly
* pass failing tests in batchedmode-test
* fix pretty/lint/import errors
* pass test-build
* nit: pull .create(null) out of the act() call
Uses a dynamic flag in www's test renderer build so we can condtionally
disable the passive effects bugfix. Matches the dynamic flag used in
the www React DOM build.
PR #15650 is a bugfix but it's technically a semantic change that could
cause regressions. I don't think it will be an issue, since the
previous behavior was both broken and incoherent, but out of an
abundance of caution, let's wrap it in a flag so we can easily revert
it if necessary.
* Failing test for false positive warning
* Flush passive effects before discrete events
Currently, we check for pending passive effects inside the `setState`
method before we add additional updates to the queue, in case those
pending effects also add things to the queue.
However, the `setState` method is too late, because the event that
caused the update might not have ever fired had the passive effects
flushed before we got there.
This is the same as the discrete/serial events problem. When a serial
update comes in, and there's already a pending serial update, we have to
do it before we call the user-provided event handlers. Because the event
handlers themselves might change as a result of the pending update.
This commit moves the `flushPassiveEffects` call to before the discrete
event handlers are called, and removes it from the `setState` method.
Non-discrete events will not cause passive effects to flush, which is
fine, since by definition they are not order dependent.
Strengthened the I/O-boundary type conversion logic.
Fixed type inconsistencies uncovered by removing `any` and
by making explicit type annotations and transformations.
In particular, these were likely malformed when restored from a file:
- `commitDetails`
- `interactions`
- `initialTreeBaseDurations`
The mismatches were Map vs interleaved Array.
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.
* 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
* 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.
* 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
This simplifies your test helpers to loop until all timers are flushed (including the ones that get queued after updates), and works in concurrent mode. I also renamed actSuspense to actAsync to be clearer.
Owners in the list may have been filtered out of the Store, but in the owners list view- it's important to still show them. The frontend cannot do this on its own, so this list needs to come from the renderer interface.
* 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
* 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)
Propagate `rootID` throughout the code for `captureScreenshot`.
Rename private profiling maps of `store` to make relations more clear.
Fix missing cleanup for screenshots data in `set importedProfilingData` of `store`.
There are many unnecessary typecasts through `any` which
break the Flow of types across the program.
It's more bulletproof to avoid lying to ourselves about types.
Also fixed sketchy null check where zero ID would be skipped:
```diff
- } else if (selectedElementID) {
+ } else if (selectedElementID !== null) {
```
https://github.com/flowtype/flow-bin/issues/138#issuecomment-448416874https://github.com/flowtype/flow-bin/issues/138#issuecomment-450367472
> This will stop flow from trying to consume too many virtual CPUs (which CircleCI doesn't actually provide), letting it run to completion without first running out of memory and killing its sub processes.
The log output in CircleCI was:
https://circleci.com/gh/bvaughn/react-devtools-experimental/201
```
#!/bin/bash -eo pipefail
yarn flow
yarn run v1.10.1
$ /home/circleci/repo/node_modules/.bin/flow
Launching Flow server for /home/circleci/repo
Spawned flow server (pid=259)
Logs will go to /tmp/flow/zShomezScirclecizSrepo.log
Monitor logs will go to /tmp/flow/zShomezScirclecizSrepo.monitor_log
Launching Flow server for /home/circleci/repo
Spawned flow server (pid=361)
Logs will go to /tmp/flow/zShomezScirclecizSrepo.log
Monitor logs will go to /tmp/flow/zShomezScirclecizSrepo.monitor_log
Launching Flow server for /home/circleci/repo
Spawned flow server (pid=464)
Logs will go to /tmp/flow/zShomezScirclecizSrepo.log
Monitor logs will go to /tmp/flow/zShomezScirclecizSrepo.monitor_log
Launching Flow server for /home/circleci/repo
Spawned flow server (pid=567)
Logs will go to /tmp/flow/zShomezScirclecizSrepo.log
Monitor logs will go to /tmp/flow/zShomezScirclecizSrepo.monitor_log
Lost connection to the flow server (0 retries remaining): -Out of retries, exiting!
error Command failed with exit code 7.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Exited with code 1
```
* [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
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.
Fixes https://github.com/bvaughn/react-devtools-experimental/issues/217
The error reproduces with any two React websites, e.g. `https://reactjs.org` and `https://nextjs.org`, by keeping the DevTools Components tab open and switching between these websites in the same browser tab.
There are several issues with the code that contribute to this:
1. `Bridge` leaves behind a dangling timer that fires `_flush` after the bridge has been abandoned ("shutdown").
2. `bridge.send('shutdown')` is asynchronous, so the event handlers do not get unsubscribed in time.
3. `port.onDisconnect` does not trigger on in-tab navigation like new URL or back/forward navigation.
4. State management design of the code that uses shared variables and callbacks makes it hard to handle race conditions originating from the browser.
This commit cleans up some of the lacking symmetry when using `addListener`/`removeListener`, but the code in `shells/browser/shared/src/main.js` is hard to reason about with regards to race conditions, and there are many possible race conditions originating from the browser, so maybe there could be a better design paradigm (like a formal state machine) to manage the state changes in response to sequences of events than plain old event listeners, callbacks, and shared variables.
Unrelated, but clicking Chrome Back/Forward/Back/Forward very fast makes the browser and the DevTools and the DevTools of DevTools stall and become unresponsive for some time, then recovers but the Back/Forward/Stop/Refresh button and favicon loading indicator may remain broken. Looks like a Chrome bug, some kind of a temporary deadlock in handling the browser history.
Flow IDE shows the original type, not the file-scoped alias,
so it's confusing to see incompatible variables that have types
with the same name.
This started from `src/devtools/ProfilingCache.js` where
`ProfilingSummary` was incompatible, but I decided to make a bigger
change for consistency and to avoid similar mistakes in the future.
Let's make impossible states truly impossible, and fix Flow types, too.
All three usages of Agent called addBridge right after constructing it.
Agent has one field `_bridge` which is force-typed as not-null despite
there's a temporary zone between the constructor end and addBridge start
where `_bridge` is null.
Fixes https://github.com/bvaughn/react-devtools-experimental/issues/131
Uses the new function `findAllCurrentHostFibers`.
Removes dependency on React's `renderer.findHostInstanceByFiber` function
which used to highlight only the first DOM element of a Fragment.
Reworked `src/backend/views/Overlay` to support highlighting
more than one element rectangle annotated with one tooltip.
Fixed minor issues with the tooltip position calculation.
This is being done to fix a drill-through bug, although the initial fix is perhaps not the most performant one. At least we have test coverage now and a temporary fix.
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.
* ADD: disablePictureInPicture attribute for HTML5 videos
* ADD: disablePictureInPicture as DOMProperty and attribute
* Update: Replace camelCase with lowercase and vice-versa
* FIX: Missing comma on attribute (prettier)
https://webpack.js.org/plugins/define-plugin/
Webpack's DefinePlugin has the ability to replace `typeof expr` to a constant in compile-time, which should lead to better dead-code-elimination.
This implements matching Fibers against the tracked selection path.
The algorithm is optimized to do as little checks as possible:
* When not trying to restore selection, we don't do anything
* When restoring selection, we only check .return pointers of new mounts
* Only when .return pointers match our current deepest match, we compare the frames
Normally, Fibers have key or index which we'll use to match things up between reloads. However, roots don't have such a concept. We'll use their insertion order as an approximation. If it's consistent, we'll be able to restore the selection.
This implements the infrastructure for saving and restoring renderer-specific selection state in the session storage.
Note this doesn't actually implement the calculation and tracking of paths in the renderer. It only simulates that the renderer can do it. The actual implementation will come in a later commit.
Bugfix for `inferPriorityFromExpirationTime` function. It happened to
work in our existing tests because we use virtual time.
Flow would have caught this if expiration times were an opaque type. We
should consider that in the future. (The downside of opaque types is
that all operations would have to go through helper functions, which may
or may not get inlined by Closure.)
Fixes a bug where the timeout passed to `scheduleCallback` represented
an absolute timestamp, instead of the amount of time until that
timestamp is reached. The solution is to subtract the current time
from the expiration.
The bug wasn't caught by other tests because we use virtual times that
default to 0, and most tests don't advance time.
I also moved the `initialTimeMs` offset to the
`SchedulerWithReactIntegration` module so that we don't have to remember
to subtract the offset every time. (We should consider upstreaming this
to the Scheduler package.)
The implementation is wrong, but also it's not that useful for
debugging. Implementing it properly would involve tracking more
information than we do currently. Perhaps including the priority
of the callback in the message would be helpful, but not sure. For now
I'll just remove it.
This commit leaves a few major things uunresolved:
* We aren't yet polling for updates
* We aren't yet using the two setState pattern
* The resource cache will grow unbounded over time because we aren't yet clearing items from it
* The renderer interface is not smart enough to avoid resending unchanged data between requests
Refactor of Press and additional regression coverage.
The logic for "start", "move", "end", and "cancel" events is consolidated into a single block to reduce duplication and improve consistency of the UX across input-types. Also reduces code size.
The bailout logic for anchor tags is removed since we preventDefault for click by default. We can discuss scenarios where it makes sense to limit functionality around interactions on anchor tags.
The logic for ignoring emulated events is simplified and improved. Pointer events can produce emulated touch (immediately after pointer) and mouse events (delayed) which is now accounted for and tested.
Selecting the tab when the mouse is pressed rather than only when it is
released makes tab switching feel faster and also matches how the Chrome dev
tools behave.
The previous tab selection handler which listens for the radio button's
selection has been kept for the benefit of interaction methods which
don't trigger the mousedown handler.
This patch makes a change to the Focus module so that it only reports
focus/blur on the host node that's a direct child of the event component. This
brings the expected behaviour in line with the browser default of focus/blur
events not bubbling for Pressable.
This doesn't change any logic, just the shape of the control flow.
I want to unify some branches at the end, so it's easier if there are no early returns.
Moves the cancelTimeout call to right before creating a new work-in-
progress root. Fixes a class of bugs where a pending commit is not
cancelled, causing an incomplete tree to accidentally commit.
In the interest of fixing downstream bugs quickly, I'm landing this
without a test case; I'll add one in a follow up.
The Pointer Events spec mentions that the value of `button` in a nativeEvent
can be anything between 0 and 5 for "down" events. We only care about those
with a value of 0.
1. Fix hiding context menu for longpress via touch.
2. Fix scrolling of viewport for longpress via spacebar key.
3. Add tests for anchor-related behaviour and preventDefault.
4. Add a deactivation delay for forced activation
5. Add pointerType to Press events.
NOTE: this currently extends pointerType to include `keyboard`.
NOTE: React Native doesn't have a deactivation delay for forced activation, but this is possibly because of the async bridge meaning that the events aren't dispatched sync.
This implementation differs from equivalents in React Native in the following ways:
1. A move during a press will not cancel onLongPress.
2. A move to outside the retention target will cancel the press and not
reactivate when moved back within the retention target.
* Track the earliest event time in this render
Rebase
* Track the time of the fallback being shown as an event time
When we switch back from fallback to content, we made progress and we track
the time from when we showed the fallback in the first place as the
last time we made progress.
* Don't retry if synchronous
* Only suspend when we switch to fallback mode
This ensures that we don't resuspend unnecessarily if we're just retrying
the same exact boundary again. We can still unnecessarily suspend
for nested boundaries.
* Rename timedOutAt to fallbackExpirationTime
* Account for suspense in devtools suspense test
The React Native build does not minify error messages in production,
but it still needs to run the error messages transform to compile
`invariant` calls to `ReactError`. To do this, I added a `noMinify`
option to the Babel plugin. I also renamed it from
`minify-error-messages` to the more generic `transform-error-messages`.
* [React Native] Add tests to paper renderer for measure, measureLayout
* [React Native] measure calls will now call FabricUIManager
The Fabric renderer was previously calling the paper UIManager's measure calls and passing the react tag. This PR changes the renderer to now call FabricUIManager passing the node instead.
One of the parts of this that feels more controversial is making NativeMethodsMixin and ReactNative.NativeComponent warn when calling measureLayout in Fabric. As Seb and I decided in https://github.com/facebook/react/pull/15126, it doesn't make sense for a component created with one of these methods to require a native ref but not work the other way around. For example: a.measureLayout(b) might work but b.measureLayout(a) wouldn't. We figure we should keep these consistent and continue migrating things off of NativeMethodsMixin and NativeComponent.
If this becomes problematic for the Fabric rollout then we should revisit this.
* Fixing Flow
* Add FabricUIManager to externals for paper renderer
* import * as FabricUIManager from 'FabricUIManager';
* Update tests
* Shouldn't have removed UIManager import
* Update with the new tests
We use bitwise operations to compute expiration times, which means they
need to be smaller than 31 bits. So we measure times relative to module
initialization, similar to `performance.now`.
This was already working in the old fiber scheduler, but we didn't have
a test for it.
If click-to-inspect then hover an element in just the right place, it flickers between two elements because this "tip" element catches the hover. This should fix it.
When an async update expires, React renders at the expiration time that
corresponds to the current time, not at the original update's expiration
time. That way, all the expired work in the tree is flushed in a
single batch.
This is implemented inside `renderRoot` by comparing the next render
expiration time to the current time. If the current time is later,
`renderRoot` will restart at the later time.
Because of poor factoring, the check is currently performed right before
entering the work loop. But the work loop is usually entered multiple
times in a single callback: each time a component throws or suspends.
This led to an infinite loop where React would detect that an update
expired, restart at the current time, make a bit of progress, suspend,
check for expired work again, and start the loop again.
I fixed this by moving the expired work check to the beginning of
`renderRoot`, so that it is not performed every time something suspends.
This isn't ideal, because you could technically still fall into a loop
if more than 10ms lapse in between exiting `renderRoot` and entering it
again. The proper fix is to lift the check outside of `renderRoot`
entirely so that the function can restart without checking for expired
work again. Since this is exceedingly unlikely (and this whole thing is
still behind a flag), I'll do the better fix in an already-planned
follow up to fork `renderRoot` into separate functions for sync and
async work.
* Add HoverProps type
* Add more Hover event module tests
* Add more Press event module tests
* Change default longPress delay from 1000 to 500
* Rename dispatchPressEvent -> dispatchEvent
* Consolidate state updates in Press event module
* Add keyboard support for Press events
* Add FocusProps type and unit tests
* Allow DevTools to toggle Suspense state
* Change API to overrideSuspense
This lets detect support for overriding Suspense from DevTools.
* Add ConcurrentMode test
* Newlines
* Remove unnecessary change
* Naming changes
* Store FB bundles as CI artifacts
Updates the Circle CI config to store Facebook bundles as build
artifacts. We already do this for our npm packages.
* Might as well store everything in build/
* Store build directory as a tarball
So it's easy to download
This doesn't rely on checking the tag. When the alternate of a parent
is missing, it assumes it's a fragment indirection and moves onto the
next parent fiber.
The Facebook build of React DOM uses a forked entry point that exposes
additional secret internals. I didn't account for this when I added
the react-dom/unstable-new-scheduler build, so the extra internals
are currently missing. This commit adds them.
Verified that a variant of this test fails as follows when the
`context.withAsyncDispatching` function is excluded (i.e., reproduces the
issue).
Expected value to equal:
["press", "longpress", "longpresschange"]
Received:
["press", "longpress", "longpress", "longpresschange"]
* Rewrite ReactFiberScheduler
Adds a new implementation of ReactFiberScheduler behind a feature flag.
We will maintain both implementations in parallel until the new one
is proven stable enough to replace the old one.
The main difference between the implementations is that the new one is
integrated with the Scheduler package's priority levels.
* Conditionally add fields to FiberRoot
Some fields only used by the old scheduler, and some by the new.
* Add separate build that enables new scheduler
* Re-enable skipped test
If synchronous updates are scheduled by a passive effect, that work
should be flushed synchronously, even if flushPassiveEffects is
called inside batchedUpdates.
* Passive effects have same priority as render
* Revert ability to cancel the current callback
React doesn't need this anyway because it never schedules callbacks if
it's already rendering.
* Revert change to FiberDebugPerf
Turns out this isn't neccessary.
* Fix ReactFiberScheduler dead code elimination
Should initialize to nothing, then assign the exports conditionally,
instead of initializing to the old exports and then reassigning to the
new ones.
* Don't yield before commit during sync error retry
* Call Scheduler.flushAll unconditionally in tests
Instead of wrapping in enableNewScheduler flag.
This took a while, but I'm happy I went through it. Some key moments - recursively flushing effects, flushing microtasks on each async turn, and my team's uncompromising philosophy on code reuse. Really happy with this. I still want to expand test coverage, and I have some more small related todos, but this is good to land. On to the next one.
Soundtrack to landing this - https://open.spotify.com/track/0MF8I8OUo8kytiOo8aSHYq?si=gSWqUheKQbiQDXzptCXHTg
* hacked up act(async () => {...})
* move stuff around
* merge changes
* abstract .act warnings and stuff. all renderers. pass all tests.
* move testutils.act back into testutils
* move into scheduler, rename some bits
* smaller bundle
* a comment for why we don't do typeof === 'function'
* fix test
* pass tests - fire, prod
* lose actContainerElement
* tighter
* write a test for TestRenderer
it's an odd one, because not only does sync act not flush effects correctly, but the async one does (wut). verified it's fine with the dom version.
* lint
* rewrote to move flushing logic closer to the renderer
the scheduler's `flushPassiveEffects` didn't work as expected for the test renderer, so I decided to go back to the hack (rendering a dumb container) This also makes reactdom not as heavy (by a few bytes, but still).
* move it around so the delta isn't too bad
* cleanups
fix promise chaining
propagate errors correctly
test for thenable the 'right' way
more tests!
tidier!
ponies!
* Stray comment
* recursively flush effects
* fixed tests
* lint, move noop.act into react-reconciler
* microtasks when checking if called, s/called/calledLog, cleanup
* pass fb lint
we could have globally changed our eslint config to assume Promise is available, but that means we expect a promise polyfill on the page, and we don't yet. this code is triggered only in jest anyway, and we're fairly certain Promise will be available there. hence, the once-off disable for the check
* shorter timers, fix a test, test for Promise
* use global.Promise for existence check
* flush microtasks
* a version that works in browsers (that support postMessage)
I also added a sanity fixture inside fixtures/dom/ mostly for me.
* hoist flushEffectsAndMicroTasks
* pull out tick logic from ReactFiberScheduler
* fix await act (...sync) hanging
- fix a hang when awaiting sync logic
- a better async/await test for test renderer
* feedback changes
- use node's setImmediate if available
- a warning if MessageChannel isn't available
- rename some functions
* pass lint/flow checks (without requiring a Promise polyfill/exclusion)
* prettier
the prettiest, even.
* use globalPromise for the missed await warning
* __DEV__ check for didWarnAboutMessageChannel
* thenables and callbacks instead of promises, pass flow/lint
* tinier. better.
- pulled most bits out of FiberScheduler
- actedUpdates uses callbacks now
* pass build validation
* augh prettier
* golfing 7 more chars
* Test that effects are not flushed without also flushing microtasks
* export doesHavePendingPassiveEffects, nits
* createAct()
* dead code
* missed in merge?
* lose the preflushing bits
* ugh prettier
* removed `actedUpdates()`, created shared/actingUpdatesScopeDepth
* rearrange imports so builds work, remove the hack versions of flushPassiveEffects
* represent actingUpdatesScopeDepth as a tuple [number]
* use a shared flag on React.__SECRET...
* remove createAct, setup act for all relevant renderers
* review feedback
shared/enqueueTask
import ReactSharedInternals from 'shared/ReactSharedInternals';
simpler act() internals
ReactSharedInternals.ReactShouldWarnActingUpdates
* move act() implementation into createReactNoop
* warnIfNotCurrentlyActingUpdatesInDev condition check order
* Add Press responder event tests
Behavior being tested takes cues from React Native's Pressability.
A couple of these tests fail and require the Press implementation to be patched.
* Add PressProps type to event module
* Move default Press event delays to constants
* Fix right-click press check for Safari
* Prettier and Linter
* Use event.key in press responder
event.keyCode is a deprecated API
* Remove unused props from Press event module
Note: this is for an experimental event API that we're testing out internally at Facebook.
* onPressIn -> onPressStart
* onPressOut -> onPressEnd
* longPressCancelsPress -> onLongPressShouldCancelPress
* ReactNative's ref.measureLayout now takes a ref
* Use Object as the additional param type
* Remove unnecessary whitespace
* Not supporting ref in mixin or subclass
Make sure that `onPressChange` is only called if `longPressCancelsPress` is `false`.
And make sure that `onLongPressChange` is called when a long press ends.
The 'longpress' event is dispatched during a press interaction, rather than
after it has ended.
The 'longPressCancelsPress' prop can be used to prevent 'press' being
dispatched if 'longpress' has already been dispatched.
I inline it into performAsyncWork instead.
Code that was only relevant to the async callback had leaked into the
performWork call which is an indication that this was a bad abstraction
and therefore the wrong place to DRY.
By inlining I also discovered that minExpirationTime is actually irrelevant
in the yieldy case so we can clean that up.
* Isolate ReactUpdates-test cases
This ensures their behavior is consistent when run in isolation, and that they actually test the cases they're describing.
* Add coverage for cases where we reset nestedUpdateCounter
These cases explicitly verify that we reset the counter in right places.
* Add a mutually recursive test case
* Add test coverage for useLayoutEffect loop
Adds a feature flag `enableNewScheduler` that toggles between two
implementations of ReactFiberScheduler. This will let us land changes in
master while preserving the ability to quickly rollback.
Ideally this will be a short-lived fork. Once we've tested the new
scheduler for a week or so without issues, we will get rid of it. Until
then, we'll need to maintain two parallel implementations and run tests
against both of them. We rarely land changes to ReactFiberScheduler, so
I don't expect this will be a huge burden.
This commit does not implement anything new. The flag is still off and
tests run against the existing implementation.
Use `yarn test-new-scheduler` to run tests against the new one.
MDN has a list of methods for obtaining the window reference of an
iframe:
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Syntax
fix(react-dom): check if iframe belongs to the same origin
Accessing the contentDocument of a HTMLIframeElement can cause the browser
to throw, e.g. if it has a cross-origin src attribute.
Safari will show an error in the console when the access results in "Blocked a frame with origin". e.g:
```javascript
try {
$0.contentDocument.defaultView
} catch (err) {
console.log('err', err)
}
> Blocked a frame with origin X from accessing a frame with origin Y. Protocols, domains, and ports must match.
> err – TypeError: null is not an object (evaluating '$0.contentDocument.defaultView')
```
A safety way is to access one of the cross origin properties: Window or Location
Which might result in "SecurityError" DOM Exception and it is compatible to Safari.
```javascript
try {
$0.contentWindow.location.href
} catch (err) {
console.log('err', err)
}
> err – SecurityError: Blocked a frame with origin "http://localhost:3001" from accessing a cross-origin frame. Protocols, domains, and ports must match.
```
https://html.spec.whatwg.org/multipage/browsers.html#integration-with-idl
* Transform invariant to custom error type
This transforms calls to the invariant module:
```js
invariant(condition, 'A %s message that contains %s', adj, noun);
```
Into throw statements:
```js
if (!condition) {
if (__DEV__) {
throw ReactError(`A ${adj} message that contains ${noun}`);
} else {
throw ReactErrorProd(ERR_CODE, adj, noun);
}
}
```
The only thing ReactError does is return an error whose name is set
to "Invariant Violation" to match the existing behavior.
ReactErrorProd is a special version used in production that throws
a minified error code, with a link to see to expanded form. This
replaces the reactProdInvariant module.
As a next step, I would like to replace our use of the invariant module
for user facing errors by transforming normal Error constructors to
ReactError and ReactErrorProd. (We can continue using invariant for
internal React errors that are meant to be unreachable, which was the
original purpose of invariant.)
* Use numbers instead of strings for error codes
* Use arguments instead of an array
I wasn't sure about this part so I asked Sebastian, and his rationale
was that using arguments will make ReactErrorProd slightly slower, but
using an array will likely make all the functions that throw slightly
slower to compile, so it's hard to say which way is better. But since
ReactErrorProd is in an error path, and fewer bytes is generally better,
no array is good.
* Casing nit
* Add more info to invalid hook call error message
* Update other renderers + change call to action
* Update related tests for new hooks error message
* Fix lint errors
* Eager bailout optimization should always compare to latest reducer
* queue.eagerReducer -> queue.lastRenderedReducer
This name is a bit more descriptive.
* Add test case that uses preceding render phase update
* Throw away old shallow renderer state on type change
This worked in function components but was broken for classes. It incorrectly retained the old instance even if the type was different.
* Remove _previousComponentIdentity
We only needed this because we didn't correctly reset based on type. Now we do so this can go away.
* Use _reset when unmounting
* Use arbitrary componentIdentity
There was no particular reason it was set to element.type. We just wanted to check if something is a render phase update.
* Support Hook state updates in shallow renderer
* Support React.memo in ReactShallowRenderer
ReactShallowRenderer uses element.type frequently, but with React.memo
elements the actual type is element.type.type. This updates
ReactShallowRenderer so it uses the correct element type for Memo
components and also validates the inner props for the wrapped
components.
* Allow Rect.memo to prevent re-renders
* Support memo(forwardRef())
* Dont call memo comparison function on initial render
* Fix test
* Small tweaks
* Set 'size' attribute to select tag if it occurs before appending options
* Add comment about why size is assigned on select create. Tests
I added some more clarification for why size must be set on select
element creation:
- In the source code
- In the DOM test fixture
- In a unit test
* Use let, not const in select tag stub assignment
* Hydration Fixture: Only load ReactDOMServer if it exists
Fixes an issue where the hydration fixture would try to load in
ReactDOMServer below version 14. In version 13, string markup methods
exist on the React namespace.
* DOM Fixtures: Use class component for App.js
This was breaking React 0.13.0.
* Hydration Fixture: better findDOMNode compatibility
This commit fixes an issue where the Hydration DOM fixture was
unusable in React 0.13.0 or lower because of newer API usage.
It fixes that by avoiding the use of refs to get the textarea
reference in the code editor component, using various versions of
findDOMNode as required.
* Hydration Fixture: Do not show dropdown for single-line errors
If an error showed for the hydration fixture, a detail element was
used even if no additional lines could display. In that case, this
commit changes the component such that it returns a div.
* Deeper React version support for hydration fixture
This commit adds support for versions 0.4.0 of React and higher for
the hydration fixture.
The DOM test fixtures themselves do not support down to React 0.4.0,
which would be exhaustive. Instead, the Hydration fixture can pick a
version to use for its own purposes. By default, this is the version
of React used by the fixtures.
In the process of doing this, I had to make some updates to the
renderer.html document associated with the hydration fixture, and I've
added some comments to better document the history of API changes.
* Prevent javascript protocol URLs
* Just warn when disableJavaScriptURLs is false
This avoids a breaking change.
* Allow framesets
* Allow <html> to be used in integration tests
Full document renders requires server rendering so the client path
just uses the hydration path in this case to simplify writing these tests.
* Detect leading and intermediate characters and test mixed case
These are considered valid javascript urls by browser so they must be
included in the filter.
This is an exact match according to the spec but maybe we should include
a super set to be safer?
* Test updates to ensure we have coverage there too
* Fix toString invocation and Flow types
Right now we invoke toString twice when we hydrate (three times
with the flag off). Ideally we should only do it once even in this case
but the code structure doesn't really allow for that right now.
* s/itRejects/itRejectsRendering
* Dedupe warning and add the unsafe URL to the warning message
* Add test that fails if g is added to the sanitizer
This only affects the prod version since the warning is deduped anyway.
* Fix prod test
* Split props changing from permanent fallback state
These will need different logic. In this commit, no logic has changed,
only moved.
* Delete terminal fallback content in first pass
If the dehydrated suspense boundary's fallback content is terminal there
is nothing to show. We need to get actual content on the screen soon.
If we deprioritize that work to offscreen, then the timeout heuristics will
be wrong.
Therefore, if we have no current and we're already at terminal fallback
state we'll immediately schedule a deletion and upgrade to real suspense.
* Show failing case when there is another wrapper boundary
* Revert "Delete terminal fallback content in first pass"
This reverts commit ad67ba8928c23f5d9ba22d7e5c202bf27d0e49d3.
* Use the new approach of leaving work at normal pri to replace fallback
* Add command to run tests in persistent mode
* Convert Suspense fuzz tester to use noop renderer
So we can run it in persistent mode, too.
* Don't mutate stateNode in appendAllChildren
We can't mutate the stateNode in appendAllChildren because the children
could be current.
This is a bit weird because now the child that we append is different
from the one on the fiber stateNode. I think this makes conceptual
sense, but I suspect this likely breaks an assumption in Fabric.
With this approach, we no longer need to clone to unhide the children,
so I removed those host config methods.
Fixes bug surfaced by fuzz tester. (The test case that failed was the
one that's already hard coded.)
* In persistent mode, disable test that reads a ref
Refs behave differently in persistent mode. I added a TODO to write
a persistent mode version of this test.
* Run persistent mode tests in CI
* test-persistent should skip files without noop
If a file doesn't reference react-noop-renderer, we shouldn't bother
running it in persistent mode, since the results will be identical to
the normal test run.
* Remove module constructor from placeholder tests
We don't need this now that we have the ability to run any test file in
either mutation or persistent mode.
* Revert "test-persistent should skip files without noop"
Seb objected to adding shelljs as a dep and I'm too lazy to worry about
Windows support so whatever I'll just revert this.
* Delete duplicate file
* Convert ReactSuspensePlaceholder tests to use noop
Instead of the test renderer, since test renderer does not support
running in persistent mode.
* Run Placeholder tests in persistent mode, too
* Fix Flow and lint
* Hidden text instances should have correct host context
Adds a test for a subtle edge case that only occurs in persistent mode.
* createHiddenTextInstance -> cloneHiddenTextInstance
This sidesteps the problem where createHiddenTextInstance needs access
to the host context.
* A clearer message for props destructuring where applicable
* Add line number to the "move function" message
* Add a hint for how to fix callbacks from props
* Simplify code and harden tests
* Collect all dependency references for better warnings
* Suggest updater or reducer where appropriate
* Import Scheduler directly, not via host config
We currently schedule asynchronous tasks via the host config. (The host
config is a static/build-time dependency injection system that varies
across different renderers — DOM, native, test, and so on.) Instead of
calling platform APIs like `requestIdleCallback` directly, each renderer
implements a method called `scheduleDeferredCallback`.
We've since discovered that when scheduling tasks, it's crucial that
React work is placed in the same queue as other, non-React work on the
main thread. Otherwise, you easily end up in a starvation scenario where
rendering is constantly interrupted by less important tasks. You need a
centralized coordinator that is used both by React and by other
frameworks and application code. This coordinator must also have a
consistent API across all the different host environments, for
convention's sake and so product code is portable — e.g. so the same
component can work in both React Native and React Native Web.
This turned into the Scheduler package. We will have different builds of
Scheduler for each of our target platforms. With this approach, we treat
Scheduler like a built-in platform primitive that exists wherever React
is supported.
Now that we have this consistent interface, the indirection of the host
config no longer makes sense for the purpose of scheduling tasks. In
fact, we explicitly do not want renderers to scheduled task via any
system except the Scheduler package.
So, this PR removes `scheduleDeferredCallback` and its associated
methods from the host config in favor of directly importing Scheduler.
* Missed an extraneous export
* Warn on mount when deps are not an array
* Check other Hooks
* I can't figure out how to fix error/warning nesting lint
But it doesn't really matter much because we test other cases in the other test.
* Revert #14756 changes to ReactFiberScheduler
This PR introduced some bugs in concurrent mode during internal testing.
Until we figure out a proper solution, I'm going to try reverting it.
Not totally certain this is sufficient to unbreak the bugs we found, but
I'm using this branch to determine that.
* Add back commented out Scheduler import
With a note not to use named imports next time we import Scheduler
in this module.
This required a bit of unusual CSS but seems to work well for Firefox and Chrome. We can remove it and revisit other approaches (like PR#24) in the future if needed.
* ReactDebugHooks identifies State and Reducer hooks as editable
* Inject overrideHookState() method to DevTools to support editing in DEV builds
* Added an integration test for React DevTools, react-debug-tools, and overrideHookState
* Swap expect(ReactNoop) for expect(Scheduler)
In the previous commits, I upgraded our custom Jest matchers for the
noop and test renderers to use Scheduler under the hood.
Now that all these matchers are using Scheduler, we can drop
support for passing ReactNoop and test roots and always pass
Scheduler directly.
* Externalize Scheduler in noop and test bundles
I also noticed we don't need to regenerator runtime in noop anymore.
* Replace test renderer's fake Scheduler implementation with mock build
The test renderer has its own mock implementation of the Scheduler
interface, with the ability to partially render work in tests. Now that
this functionality has been lifted into a proper mock Scheduler build,
we can use that instead.
* Fix Profiler tests in prod
* Replace noop's fake Scheduler implementation with mock Scheduler build
The noop renderer has its own mock implementation of the Scheduler
interface, with the ability to partially render work in tests. Now that
this functionality has been lifted into a proper mock Scheduler build,
we can use that instead.
Most of the existing noop tests were unaffected, but I did have to make
some changes. The biggest one involved passive effects: previously, they
were scheduled on a separate queue from the queue that handles
rendering. After this change, both rendering and effects are scheduled
in the Scheduler queue. I think this is a better approach because tests
no longer have to worry about the difference; if you call `flushAll`,
all the work is flushed, both rendering and effects. But for those few
tests that do care to flush the rendering without the effects, that's
still possible using the `yieldValue` API.
Follow-up: Do the same for test renderer.
* Fix import to scheduler/unstable_mock
* Add new mock build of Scheduler with flush, yield API
Test environments need a way to take control of the Scheduler queue and
incrementally flush work. Our current tests accomplish this either using
dynamic injection, or by using Jest's fake timers feature. Both of these
options are fragile and rely too much on implementation details.
In this new approach, we have a separate build of Scheduler that is
specifically designed for test environments. We mock the default
implementation like we would any other module; in our case, via Jest.
This special build has methods like `flushAll` and `yieldValue` that
control when work is flushed. These methods are based on equivalent
methods we've been using to write incremental React tests. Eventually
we may want to migrate the React tests to interact with the mock
Scheduler directly, instead of going through the host config like we
currently do.
For now, I'm using our custom static injection infrastructure to create
the two builds of Scheduler — a default build for DOM (which falls back
to a naive timer based implementation), and the new mock build. I did it
this way because it allows me to share most of the implementation, which
isn't specific to a host environment — e.g. everything related to the
priority queue. It may be better to duplicate the shared code instead,
especially considering that future environments (like React Native) may
have entirely forked implementations. I'd prefer to wait until the
implementation stabilizes before worrying about that, but I'm open to
changing this now if we decide it's important enough.
* Mock Scheduler in bundle tests, too
* Remove special case by making regex more restrictive
* Refactor hook ordering check to use DEV-only data structure. This enables us to warn about more cases (e.g. useContext, useDebugValue) withou the need to add any overhead to production bundles.
* Throw in tests if work is done before emptying log
Test renderer already does this. Makes it harder to miss unexpected
behavior by forcing you to assert on every logged value.
* Convert ReactNoop tests to use jest matchers
The matchers warn if work is flushed while the log is empty. This is
the pattern we already follow for test renderer. I've used the same APIs
as test renderer, so it should be easy to switch between the two.
* Deprecate ref.setNativeProps in favor of ReactNative.setNativeProps
* Using a feature flag for the setNativeProps warning
* Removing extra line breaks
* Set the FB native feature flag to true
* Prettier
* Remove ReactNoop.flushDeferredPri and flushUnitsOfWork
Some of our older tests worked by counting how many times React checked
whether it should yield to the main thread, instead of something
publicly observable like how many times a component is rendered.
Our newer tests have converged on a style where we push into a log and
make assertions on the log. This pattern is less coupled to the
implementation while still being sufficient to test performance
optimizations, like resuming (whenever we add that back).
This commit removes flushDeferredPri and flushUnitsOfWork and upgrades
the affected tests.
* Remove shouldYieldToRenderer indirection
This wrapper is no longer necessary.
As I prepare to refactor the Fiber scheduler, I've noticed some quirks
in our implementation. This PR addressed one of them.
---
There's no reason for a timed out Scheduler callback to check
`shouldYield`, because the value will always be false until the work
has completed. The `didTimeout` argument provides this information to
the callback so it can avoid the redundant checks.
React's existing check for whether a callback has timed out didn't make
any sense, but happened to work anyway. I don't think the wrongness of
the old implementation is observable via React APIs but it's
incoherent regardless.
* Adding ReactNative.setNativeProps that takes a ref
* Adding test for components rendered with Fabric with Paper's setNativeProps
* Fixing flow types
* Fix prettier
* Rename ReactNativeSetNativeProps.js to be more general
* Add ESLint rule for useEffect/useCallback/useMemo Hook dependencies
* Fix ReactiveDependencies rule
* fix lint errors
* Support useLayoutEffect
* Add some failing tests and comments
* Gather dependencies in child scopes too
* If we don't find foo.bar.baz in deps, try foo.bar, then foo
* foo is enough for both foo.bar and foo.baz
* Shorter rule name
* Add fixable meta
* Remove a bunch of code and start from scratch
* [WIP] Only report errors from dependency array
This results in nicer editing experience. Also has autofix.
* Fix typo
* [Temp] Skip all tests
* Fix the first test
* Revamp the test suite
* Fix [foo] to include foo.bar
* Don't suggest call expressions
* Special case 'current' for refs
* Don't complain about known static deps
* Support useImperativeHandle
* Better punctuation and formatting
* More uniform message format
* Treat React.useRef/useState/useReducer as static too
* Add special message for ref.current
* Add a TODO case
* Alphabetize the autofix
* Only alphabetize if it already was
* Don't add static deps by default
* Add an undefined variable case
* Tweak wording
* Rename to exhaustive-deps
* Clean up / refactor a little bit
* Replace SSR fallback content with new suspense content
* The three states of a Dehydrated Suspense
This introduces three states for dehydrated suspense boundaries
Pending - This means that the tree is still waiting for additional data or
to be populated with its final content.
Fallback - This means that the tree has entered a permanent fallback state
and no more data from the server is to be expected. This means that the
client should take over and try to render instead. The fallback nodes will
be deleted.
Normal - The node has entered its final content and is now ready to be
hydrated.
* Rename retryTimedOutBoundary to resolveRetryThenable
This doesn't just retry. It assumes that resolving a thenable means that
it is ok to clear it from the thenable cache.
We'll reuse the retryTimedOutBoundary logic separately.
* Register a callback to be fired when a boundary changes away from pending
It's now possible to switch from a pending state to either hydrating
or replacing the content.
* Improve release script process documentation
* Improved pre-publish instructions/message based on feedback
* Added reminder to attach build artifacts to GitHub release
* Basic partial hydration test
* Render comments around Suspense components
We need this to be able to identify how far to skip ahead if we're not
going to hydrate this subtree yet.
* Add DehydratedSuspenseComponent type of work
Will be used for Suspense boundaries that are left with their server
rendered content intact.
* Add comment node as hydratable instance type as placeholder for suspense
* Skip past nodes within the Suspense boundary
This lets us continue hydrating sibling nodes.
* A dehydrated suspense boundary comment should be considered a sibling
* Retry hydrating at offscreen pri or after ping if suspended
* Enter hydration state when retrying dehydrated suspense boundary
* Delete all children within a dehydrated suspense boundary when it's deleted
* Delete server rendered content when props change before hydration completes
* Make test internal
* Wrap in act
* Change SSR Fixture to use Partial Hydration
This requires the enableSuspenseServerRenderer flag to be manually enabled
for the build to work.
* Changes to any parent Context forces clearing dehydrated content
We mark dehydrated boundaries as having child work, since they might have
components that read from the changed context.
We check this in beginWork and if it does we treat it as if the input
has changed (same as if props changes).
* Wrap in feature flag
* Treat Suspense boundaries without fallbacks as if not-boundaries
These don't come into play for purposes of hydration.
* Fix clearing of nested suspense boundaries
* ping -> retry
Co-Authored-By: sebmarkbage <sebastian@calyptus.eu>
* Typo
Co-Authored-By: sebmarkbage <sebastian@calyptus.eu>
* Use didReceiveUpdate instead of manually comparing props
* Leave comment for why it's ok to ignore the timeout
* Add 16.8.0 changelog
* Mention ESLint plugin
* Remove experimental notices from the ESLint plugin README
* Update CHANGELOG.md
* Add more details for Hooks
* fix
* Set a date
* Update CHANGELOG.md
Co-Authored-By: gaearon <dan.abramov@gmail.com>
* Update CHANGELOG.md
* useReducer in changelog
* Add to changelog
* Update date
* Add #14119 to changelog
* Add #14744 to changelog
* Fix PR links
* act() method was added to test utils, too
* Updated release date to February 6th
* Add Scheduler.unstable_next
* Use Scheduler to prioritize updates
Changes the implementation of syncUpdates, deferredUpdates, and
interactiveUpdates to use runWithPriority, so
This is the minimum integration between Scheduler and React needed to
unblock use of the Scheduler.next API.
* Add Scheduler.unstable_next
* Use Scheduler to prioritize updates
Changes the implementation of syncUpdates, deferredUpdates, and
interactiveUpdates to use runWithPriority, so
This is the minimum integration between Scheduler and React needed to
unblock use of the Scheduler.next API.
* Add 16.8.0 changelog
* Mention ESLint plugin
* Remove experimental notices from the ESLint plugin README
* Update CHANGELOG.md
* Add more details for Hooks
* fix
* Set a date
* Update CHANGELOG.md
Co-Authored-By: gaearon <dan.abramov@gmail.com>
* Update CHANGELOG.md
* useReducer in changelog
* Add to changelog
* Update date
* Add #14119 to changelog
* Add #14744 to changelog
* Fix PR links
* act() method was added to test utils, too
* Updated release date to February 6th
* Add 16.8.0 changelog
* Mention ESLint plugin
* Remove experimental notices from the ESLint plugin README
* Update CHANGELOG.md
* Add more details for Hooks
* fix
* Set a date
* Update CHANGELOG.md
Co-Authored-By: gaearon <dan.abramov@gmail.com>
* Update CHANGELOG.md
* useReducer in changelog
* Add to changelog
* Update date
* Add #14119 to changelog
* Add #14744 to changelog
* Fix PR links
* act() method was added to test utils, too
* Updated release date to February 6th
* expose unstable_interact for batching actions in tests
* move to TestUtils
* move it all into testutils
* s/interact/act
* warn when calling hook-like setState outside batching mode
* pass tests
* merge-temp
* move jsdom test to callsite
* mark failing tests
* pass most tests (except one)
* augh IE
* pass fuzz tests
* better warning, expose the right batchedUpdates on TestRenderer for www
* move it into hooks, test for dom
* expose a flag on the host config, move stuff around
* rename, pass flow
* pass flow... again
* tweak .act() type
* enable for all jest environments/renderers; pass (most) tests.
* pass all tests
* expose just the warning from the scheduler
* don't return values
* a bunch of changes.
can't return values from .act
don't try to await .act calls
pass tests
* fixes and nits
* "fire events that udpates state"
* nit
* 🙄
* my bad
* hi andrew
(prettier fix)
* Avoid importing Scheduler directly
The reconciler should not depend directly on Scheduler. This adds it to
the host config for the renderer instead.
(Except for `scheduler/tracing` imports, which are used only by the
profiling build. I've left those imports as-is, though I'm open to
directing those through the host config, too.)
* Make throwaway root id longer to appease Brian
* Restrict effect return type to a function or nothing
We already warn in dev if the wrong type is returned. This updates the
Flow type.
* Restrict return type further
* Assume Effect hook returns either a function or undefined
* Tweak warning message
* Improve Reducer Hook's lazy init API
* Use generic type for initilizer input
Still requires an `any` cast in the case where `init` function is
not provided.
* Move DEV-only function right above where it's used
I don't like looking at this top-level function #petty
* Use different dispatchers for functions & classes
Classes support readContext, but not any of the other dispatcher
methods. Function support all methods.
This is a more robust version of our previous strategy of checking
whether `currentlyRenderingFiber` is null.
As a next step, we can use a separate dispatcher for each phase of the
render cycle (mount versus update).
* Use separate dispatchers for mount and update
* Remove mount code from update path
Deletes mount-specific code from the update path, since it should be
unreachable. To continue supporting progressive enhancement (mounting
new hooks at the end of the list), we detect when there are no more
current hooks and switch back to the mount dispatcher. Progressive
enhancement isn't officially supported yet, so it will continue to warn.
* Factoring nits
* Fix Flow
Had to cheat more than I would like
* More Flow nits
* Switch back to using a special dispatcher for nested hooks in DEV
In order for this strategy to work, I had to revert progressive
enhancement support (appending hooks to the end). It was previously a
warning but now it results in an error. We'll reconsider later.
* Always pass args to updateState and updateReducer
Even though the extra args are only used on mount, to ensure
type consistency.
* Make readContext() in Hooks DEV-only warning
* Warn about readContext() during class render-phase setState()
* Warn on readContext() in SSR inside useMemo and useReducer
* Make all Hooks-in-Hooks warnings DEV-only
* Rename stashContextDependencies
* Clean up warning state on errors
* Turned enableHooks feature flag on everywhere
* Removed useHooks feature flag from tests (now that it's on by default)
* Remove useHooks feature flag entirely
* Revert "Revert "Double-render function components with Hooks in DEV in StrictMode" (#14652)"
This reverts commit 3fbebb2a0b.
* Revert "Revert "Disallow reading context during useMemo etc" (#14651)"
This reverts commit 5fce6488ce.
* Add extra passing test for an edge case
Mentioned by @acdlite to watch out for
* More convoluted test
* Don't rely on expirationTime
Addresses @acdlite's concerns
* Edge case: forbid readContext() during eager reducer
* warn when returning different hooks on next render
like it says. adds a field to Hook to track effect 'type', and compares when cloning subsequently.
* lint
* review changes
- numbered enum for hook types
- s/hookType/_debugType
- better dce
* cleaner detection location
* redundant comments
* different EffectHook / LayoutEffectHook
* prettier
* top level currentHookType
* nulling currentHookType
need to verify dce still works
* small enhancements
* hook order checks for useContext/useImperative
* prettier
* stray whitespace
* move some bits around
* better errors
* pass tests
* lint, flow
* show a before - after diff
* an error stack in the warning
* lose currentHookMatches, fix a test
* tidy
* clear the mismatch only in dev
* pass flow
* side by side diff
* tweak warning
* pass flow
* dedupe warnings per fiber, nits
* better format
* nit
* fix bad merge, pass flow
* lint
* missing hooktype enum
* merge currentHookType/currentHookNameInDev, fix nits
* lint
* final nits
* Revert "Revert "Disallow reading context during useMemo etc" (#14651)"
This reverts commit 5fce6488ce.
* Revert "Add test coverage for readContext() on the server (#14649)"
This reverts commit fe2ecd276e.
* Revert "Warn about incorrect use of useImperativeHandle() (#14647)"
This reverts commit 8f45a7fdc4.
* Revert "Disallow reading context during useMemo etc (#14648)"
This reverts commit 1fcbd22431.
* Revert "Warn about refs on lazy function components (#14645)"
This reverts commit 2a084f51a9.
* Revert "Fix typo (#14560)"
This reverts commit b5a3df6e88.
* Revert "fix typo (#14316)"
This reverts commit 9c146e6751.
* Revert "Mention forwardRef() in <Fn ref={...} /> errors and warnings (#14644)"
This reverts commit baa6d40fc8.
* Revert "Double-render function components with Hooks in DEV in StrictMode (#14643)"
This reverts commit a1414e8949.
* Revert "Add test coverage for readContext() on the server (#14649)"
This reverts commit fe2ecd276e.
* Revert "Warn about incorrect use of useImperativeHandle() (#14647)"
This reverts commit 8f45a7fdc4.
* Revert "Disallow reading context during useMemo etc (#14648)"
This reverts commit 1fcbd22431.
* Rename context variables
I just spent half an hour debugging why readContext(PurpleContext) doesn't work.
* Add test coverage for readContext() on the server
* Disallow reading context during useMemo etc
* Continue allowing readContext() in classes and context consumers
The previous commit check was too broad and incorrectly restricted classes from calling readContext(). This check is more precise and only targets components that are Hook-capable. It exploits the fact that `renderExpirationTime` is never `NoWork` after `renderWithHooks` -- something we already rely on.
* Double-render functions in strict mode
* Double-invoke first function component render too
* Mark TestRendererAsync test as internal and revert changes to it
TestRenderer is built with strict mode doublerender off.
We could change that but I'm not sure we want to. So I'll just flip the flag off for this test.
* Only double-invoke components using Hooks
* Revert unintentional change
* Fix handling of sync rejection
Reverts #14632 and adds a regression test.
* Handle rejection synchronously too
Fewer footguns and seems like nicer behavior anyway.
Specifying the directory as part of the `repository` field in a `package.json`
allows third party tools to provide better support when working with monorepos.
For example, it allows them to correctly construct a commit diff for a specific
package.
This format was accepted by npm in https://github.com/npm/rfcs/pull/19.
* Warn when mixing createRoot() and old APIs
* Move container checks to entry points
This way further warning check doesn't crash on bad inputs.
* Fix Flow
* Rename flag to be clearer
* managed by -> passed to
* Revert accidental change
* Fix Fire shim to match
* Don't bother comparing constructor when deps are not provided
When no dependencies are passed to an effect hook, what we used to do is
compare the effect constructor. If there was no change, then we would
skip firing the effect. In practice, this is a useless optimization
because the constructor will always be different when you pass an inline
closure. And if you don't pass an inline closure, then you can't access
any props or state.
There are some edge cases where an effect that doesn't close over props
or state could be useful, like reference counting the number of mounted
components. But those are rare and can be addressed by passing an empty
array of dependencies.
By removing this "optimization," we can avoid retaining the constructor
in the majority of cases where it's a closure that changes on
every render.
I made corresponding changes to the other hooks that accept
dependencies, too (useMemo, useCallback, and useImperativeHandle).
* Improve hook dependencies warning
It now includes the name of the hook in the message.
* Nits
* Allow useReducer to bail out of rendering by returning previous state
This is conceptually similar to `shouldComponentUpdate`, except because
there could be multiple useReducer (or useState) Hooks in a single
component, we can only bail out if none of the Hooks produce a new
value. We also can't bail out if any the other types of inputs — state
and context — have changed.
These optimizations rely on the constraint that components are pure
functions of props, state, and context.
In some cases, we can bail out without entering the render phase by
eagerly computing the next state and comparing it to the current one.
This only works if we are absolutely certain that the queue is empty at
the time of the update. In concurrent mode, this is difficult to
determine, because there could be multiple copies of the queue and we
don't know which one is current without doing lots of extra work, which
would defeat the purpose of the optimization. However, in our
implementation, there are at most only two copies of the queue, and if
*both* are empty then we know that the current queue must be.
* Add test for context consumers inside hidden subtree
Should not bail out during subsequent update. (This isn't directly
related to this PR because we should have had this test, anyway.)
* Refactor to use module-level variable instead of effect bit
* Add test combining state bailout and props bailout (memo)
Fixes https://github.com/facebook/react/issues/14583
Using `new Set([iterable])` does not work with IE11's non-compliant Set
implementation. By avoiding this pattern we don't need to require a Set
polyfill for IE11
* react-debug-tools accepts currentDispatcher ref as param
* ReactDebugHooks injected dispatcher ref is optional
* Support custom values for custom hooks
* PR feedback:
1. Renamed useDebugValueLabel hook to useDebugValue
2. Wrapped useDebugValue internals in if-DEV so that it could be removed from production builds.
* PR feedback:
1. Fixed some minor typos
2. Added inline comment explaining the purpose of rollupDebugValues()
3. Refactored rollupDebugValues() to use a for loop rather than filter()
4. Improve check for useDebugValue hook to lessen the chance of a false positive
5. Added optional formatter function param to useDebugValue
* Nitpick renamed a method
I don't think "array or iterator" is adding anything, and it may well be confusing, especially since this is one of the first and most common warnings that devs see.
* Memoize promise listeners to prevent exponential growth
Previously, React would attach a new listener every time a promise is
thrown, regardless of whether the same listener was already attached
during a previous render. Because React attempts to render every time
a promise resolves, the number of listeners grows quickly.
This was especially bad in synchronous mode because the renders that
happen when the promise pings are not batched together. So if a single
promise has multiple listeners for the same root, there will be multiple
renders, which in turn results in more listeners being added to the
remaining unresolved promises. This results in exponential growth in
the number of listeners with respect to the number of IO-bound
components in a single render.
Fixes#14220
* Memoize on the root and Suspense fiber instead of on the promise
* Add TODO to fix persistent mode tests
* Inject overrideProps() fn to DevTools
This function will enable editing props for function components, host nodes, and special types like memo and forwardRef.
* [Fizz] Add Flow/Jest/Rollup build infra
Add a new package for react-stream which allows for custom server renderer
outputs. I picked the name because it's a reasonable name but also
because the npm name is currently owned by a friend of the project.
The react-dom build has its own inlined server renderer under the
name `react-dom/fizz`.
There is also a noop renderer to be used for testing. At some point
we might add a public one to test-renderer but for now I don't want to have
to think about public API design for the tests.
* Add FormatConfig too
We need to separate the format (DOM, React Native, etc) from the host
running the server (Node, Browser, etc).
* Basic wiring between Node, Noop and DOM configs
The Node DOM API is pipeToNodeStream which accepts a writable stream.
* Merge host and format config in dynamic react-stream entry point
Simpler API this way but also avoids having to fork the wrapper config.
Fixes noop builds.
* Add setImmediate/Buffer globals to lint config
Used by the server renderer
* Properly include fizz.node.js
Also use forwarding to it from fizz.js in builds so that tests covers
this.
* Make react-stream private since we're not ready to publish
or even name it yet
* Rename Renderer -> Streamer
* Prefix react-dom/fizz with react-dom/unstable-fizz
* Add Fizz Browser host config
This lets Fizz render to WHATWG streams. E.g. for rendering in a
Service Worker.
I added react-dom/unstable-fizz.browser as the entry point for this.
Since we now have two configurations of DOM. I had to add another
inlinedHostConfigs configuration called `dom-browser`. The reconciler
treats this configuration the same as `dom`. For stream it checks
against the ReactFizzHostConfigBrowser instead of the Node one.
* Add Fizz Browser Fixture
This is for testing server rendering - on the client.
* Lower version number to detach it from react-reconciler version
* Fixes#14360 and adds a test for mixed priority dispatches.
It was broken because `cloneHook` assigned `memoizedState` instead of
`baseState` from the original hook to `baseState` of the clone.
* tweak comments
* Add a test for current defaultProps behavior in lazy
* Add a warning against definining defaultProps on the outer wrapper
* Warn about setting propTypes too
* Remove redundant async
* Validate propTypes for resolved lazy types
Note this only works for elements created after resolving. So it's not ideal. But it provides the best stack trace for those cases.
* Add a test for lazy(forwardRef()) propTypes check
* Validate memo() inner propTypes and warn about shadowing
* Add test verifying nested lazy is unsupported
* Change error wording to remove "Promise elements"
* Improve error message for nested lazy() and add tests
* Validate propTypes for memo in the reconciler when necessary
* Add comments for why we're calling checkPropTypes
* Fix Flow and lint
* Undo unintentional formatting changes
* Remove unnecessary case (it is handled by function code path)
* Add test coverage for memo(fn.defaultProps).propTypes
* Test should be agnostic of where resolving happens
That's an implementation detail and we might want to change it later. Let's keep it easy by making tests just check that validation happened, not at which stage.
* Unify traversal logic in createElement
This moves all type traversal into createElement. When lazy resolves, we call createElement once to re-check.
* Match prod behavior for propTypes/defaultProps shims closer
* Revert "Unify traversal logic in createElement"
This reverts commit 2e77ca47fe80ebe6595333542a8c5c138c68643f.
See https://github.com/facebook/react/pull/14298#issuecomment-442687775
* Undo unnecessary change to getComponentName
useMutationEffect has problems (namely, refs aren't attached at the time that it runs) and we're not positive it's necessary. useLayoutEffect runs at the same time as componentDidMount/Update so it's sufficient for all existing use cases; it can be used in any case that useEffect happens too late. Until we figure out what we want to do, let's delete it.
Regression introduced in #14182 resulted in errors no longer being emitted on streams, breaking many consumers.
Co-authored-by: Elliot Jalgard <elliot.j@live.se>
* Add failing test for defaultProps between lazy() and memo()
* Add another regression test for defaultProps resolution order
* Resolve outer props for MemoComponent
Whenever we do this, Rollup needs to materialize this as an object.
This causes it to also add the Babel compatibility property which is
unnecessary bloat. However, since when we use these, we leak the object
this often also deopts any compiler optimizations.
If we really need an object we should export default an object.
Currently there is an exception for DOMTopLevelEventTypes since
listing out the imports is a PITA and it doesn't escape so it should
get properly inlined. We should probably move to a different pattern
to avoid this for consistency though.
In the process of switching to MessageChannel, it seems the postMessage call was modified to pass `"*"` (originally the target origin value from `window.postMessage`). This actually ends up triggering serialization, whereas passing `undefined` bypasses.
To save some investigation, passing a Number like `0` still incurs serialization overhead - `undefined` has special behavior.
Disables the recently introduced (#14181) warning for shorthand
CSS property collisions by wrapping in a feature flag. Let's hold off
shipping this until at least the next minor.
* Add a checkbox to fixtures UI to choose React production build
* Assign header__label class name to label directly, instead of using a separate span
* center the production checkbox vertically
Scheduler needs to schedule a task that fires after paint. To do this,
it currently posts a message event to `window`. This happens on every
frame until the queue is empty. An unfortunate consequence is that every
other message event handler also gets called on every frame; even if
they exit immediately, this adds up to significant per-frame overhead.
Instead, we'll create a MessageChannel and post to that, with a
fallback to the old behavior if MessageChannel does not exist.
I figured out a simpler way to do #14181. It does allocate some but I think that's OK. Time complexity might even be better since we avoid the nested loops the old one had.
* BUG: ReactPartialRenderer / New Context polutes mutable global state
The new context API stores the provided values on the shared context instance. When used in a synchronous context, this is not an issue. However when used in an concurrent context this can cause a "push provider" from one react render to have an effect on an unrelated concurrent react render.
I've encountered this bug in production when using renderToNodeStream, which asks ReactPartialRenderer for bytes up to a high water mark before yielding. If two Node Streams are created and read from in parallel, the state of one can polute the other.
I wrote a failing test to illustrate the conditions under which this happens.
I'm also concerned that the experimental concurrent/async React rendering on the client could suffer from the same issue.
* Use unique thread ID for each partial render to access Context
This first adds an allocator that keeps track of a unique ThreadID index
for each currently executing partial renderer. IDs are not just growing
but are reused as streams are destroyed.
This ensures that IDs are kept nice and compact.
This lets us use an "array" for each Context object to store the current
values. The look up for these are fast because they're just looking up
an offset in a tightly packed "array".
I don't use an actual Array object to store the values. Instead, I rely
on that VMs (notably V8) treat storage of numeric index property access
as a separate "elements" allocation.
This lets us avoid an extra indirection.
However, we must ensure that these arrays are not holey to preserve this
feature.
To do that I store the _threadCount on each context (effectively it takes
the place of the .length property on an array).
This lets us first validate that the context has enough slots before we
access the slot. If not, we fill in the slots with the default value.
This is one of the most insidious quirks of React DOM that people run into. Now we warn when we think an update is dangerous.
We still allow rendering `{background, backgroundSize}` with unchanging values, for example. But once you remove either one or change `background` (without changing `backgroundSize` at the same time), that's bad news. So we warn.
Fixes#6348.
Oopsie!
This could have been avoided if our types were modeled correctly with
Flow (using a disjoint union).
Fuzz tester didn't catch it because it does not generate cases where
a Suspense component mounts with no children. I'll update it.
* Don't warn if an unmounted component is pinged
* Suspense fuzz tester
The fuzzer works by generating a random tree of React elements. The tree
two types of custom components:
- A Text component suspends rendering on initial mount for a fuzzy
duration of time. It may update a fuzzy number of times; each update
supsends for a fuzzy duration of time.
- A Container component wraps some children. It may remount its children
a fuzzy number of times, by updating its key.
The tree may also include nested Suspense components.
After this tree is generated, the tester sets a flag to temporarily
disable Text components from suspending. The tree is rendered
synchronously. The output of this render is the expected output.
Then the tester flips the flag back to enable suspending. It renders the
tree again. This time the Text components will suspend for the amount of
time configured by the props. The tester waits until everything has
resolved. The resolved output is then compared to the expected output
generated in the previous step.
Finally, we render once more, but this time in concurrent mode. Once
again, the resolved output is compared to the expected output.
I tested by commenting out various parts of the Suspense implementation
to see if broke in the expected way. I also confirmed that it would have
caught #14133, a recent bug related to deletions.
* When a generated test case fails, log its input
* Moar fuzziness
Adds more fuzziness to the generated tests. Specifcally, introduces
nested Suspense cases, where the fallback of a Suspense component
also suspends.
This flushed out a bug (yay!) whose test case I've hard coded.
* Use seeded random number generator
So if there's a failure, we can bisect.
* Add failing test for ping on unmounted component
We had a test for this, but not outside of concurrent mode :)
* Don't warn if an unmounted component is pinged
* Parse build script type and package names
This ensures that `yarn build core dom` includes DOM.
It also ensures that spaces like `yarn build "core, dom"` doesn't build EVERYTHING.
* Get rid of label in bundles config
Instead we just use the name from entry using fuzzy search.
There is one special case. If you put in `/index` or `/index.js`.
That allows to build things like `react/index` to only build isomorphic
where as `react` would build everything. Or `react-dom/index` to exclude
the server renderers.
* Instead of matching `/index.js` just append it to the search string
That way things like `yarn build react/` works too.
* Fixed `treeBaseDuration` by propagating its value from the suspended tree to the Fragment React temporarily wraps around it when showing the fallback UI.
* Fixed `actualDuration` by recording elapsed profiler time in the event of an error.
* Fixed `actualDuration` in concurrent mode by propagating the time spent rendering the suspending component to its parent.
Also updated ReactSuspensePlaceholder-test.internal to cover these new cases.
Fixes a bug where deletion effects in the primary tree were dropped
before entering the second render pass.
Because we no longer reset the effect list after the first render pass,
I've also moved the deletion of the fallback children to the complete
phase, after the tree successfully renders without suspending.
Will need to revisit this heuristic when we implement resuming.
* Recover from errors with a boundary in completion phase
* Use a separate field for completing unit of work
* Use a simpler fix with one boolean
* Reoder conditions
* Clarify which paths are DEV-only
* Move duplicated line out
* Make it clearer this code is DEV-only
Adds a check to the existing fuzz tester to confirm that the props are
set to the latest values in the commit phase. Only checks
componentDidUpdate; we already have unit tests for the other lifecycles,
so I think this is good enough. This is only a redundancy.
* Resolve defaultProps for Lazy components
* Make test fail again
* Undo the partial fix
* Make test output more compact
* Add a separate failing test for sync mode
* Clean up tests
* Add another update to both tests
* Resolve props for commit phase lifecycles
* Resolve prevProps for begin phase lifecycles
* Resolve prevProps for pre-commit lifecycles
* Only resolve props if element type differs
* Fix Flow
* Don't set instance.props/state during commit phase
This is an optimization. I'm not sure it's entirely safe. It's probably worth running internal tests and see if we can ever trigger a case where they're different.
This can mess with resuming.
* Keep setting instance.props/state before unmounting
This reverts part of the previous commit. It broke a test that verifies we use current props in componentWillUnmount if the fiber unmounts due to an error.
Setting to null isn't correct; setting to '' is. I opted to use dangerousStyleValue for consistency with the main path that we set things.
Fixes#14114.
Test Plan:
Verified setting to '' works in Chrome and IE11. (Setting to null works in Chrome but not in IE11.)
The `enableHooks` feature flag used to only control whether the API
was exposed on the React package. But now it also determines if the
dispatcher and implementation are included in the bundle.
We're using hooks in www, so I've switched the feature flag to `true`
in the www build.
(Alternatively, we could have two feature flags: one for the
implementation and dispatcher, and one for exposing the API on the
React package.)
* Avoid double commit by re-rendering immediately and reusing children
To support Suspense outside of concurrent mode, any component that
starts rendering must commit synchronously without being interrupted.
This means normal path, where we unwind the stack and try again from the
nearest Suspense boundary, won't work.
We used to have a special case where we commit the suspended tree in an
incomplete state. Then, in a subsequent commit, we re-render using the
fallback.
The first part — committing an incomplete tree — hasn't changed with
this PR. But I've changed the second part — now we render the fallback
children immediately, within the same commit.
* Add a failing test for remounting fallback in sync mode
* Add failing test for stuck Suspense fallback
* Toggle visibility of Suspense children in mutation phase, not layout
If parent reads visibility of children in a lifecycle, they should have
already updated.
This is required to use lazy.
Test Plan:
* Verified lazy works on a real world use case (shows spinner, shows real content).
* Verified that if I change the primary content's styles to have `display: 'none'` then it never appears (i.e., the code in `unhide` reads the styles successfully)
* Add debug tools package
* Add basic implementation
* Implement inspection of the current state of hooks using the fiber tree
* Support useContext hooks inspection by backtracking from the Fiber
I'm not sure this is safe because the return fibers may not be current
but close enough and it's fast.
We use this to set up the current values of the providers.
* rm copypasta
* Use lastIndexOf
Just in case. I don't know of any scenario where this can happen.
* Support ForwardRef
* Add test for memo and custom hooks
* Support defaultProps resolution
Check for existence of `setTimeout` and `clearTimeout` in the runtime
before using them, to ensure runtimes without them (like .NET ClearScript)
do not crash just by importing `react-dom`.
Mostly to catch this:
```js
useEffect(async () => {
// ...
return cleanup;
});
```
Is this too restrictive? Not sure if you would want to do like
```js
useEffect(() => ref.current.style.color = 'red');
```
which would give a false positive here. We can always relax it to only warn on Promises if people complain.
* Simplify imports in ReactChildFiber
* Import type first in ReactCurrentFiber
* Simplify imports in ReactFiberBeginWork
* Simplify imports in ReactFiberScheduler
* Simplify import in ReactFiberTreeReflection
* Simplify import in ReactFiberUnwindWork
* Remove repeated import
* Fix imports from ReactFiberExpirationTime
* Master imports in ReactFiberBeginWork
Removes the `enableDispatchCallback` feature flag and deletes the
associated code. An earlier version of the Hooks proposal included this
feature but we've since decided to remove it.
* [scheduler] Deadline object -> shouldYield
Instead of using a requestIdleCallback-style deadline object, expose a
method Scheduler.shouldYield that returns true if there's a higher
priority event in the queue.
* Nits
Even though we commit the fiber in an incomplete state, we shouldn't
fire any lifecycles or effects.
We already did this for classes, but now with useEffect, the same is
needed for other types of work, too.
Before the fix, the passive effect in the test is never executed.
We were previously waiting until the next commit phase to run effects. Now, we run them before scheduling work.
Effects scheduled by useEffect should not fire until after the browser
has had a chance to paint. However, they should be fired before any
subsequent mutations.
Also adds useMutationEffect and useLayoutEffect. useMutationEffect fires
during the host update phase. useLayoutEffect fires during the post-
update phase (the same phase as componentDidMount
and componentDidUpdate).
* [react-cache] Remove `cache` as argument to `read`
Updated is API is `Resource.read(key)` instead of
`Resource.read(cache, key)`.
The cache is read from context using `readContext`.
This also removes cache invalidation entirely (other than the default
LRU mechanism), as well as the ability to have multiple caches. We'll
add it back once `Context.write` lands and we can implement it the
right way.
Since there's now only a single cache (the global one), we don't
actually need to use context yet, but I've added a dummy context
anyway so the user gets an error if they attempt to read outside the
render phase.
* nits
* Add test for thenables that resolve multiple times
* [Synchronous Suspense] Suspending a class outside concurrent mode
When a class component suspends during mount outside concurrent mode,
change the tag so it's not mistaken for a completed component. For
example, we should not call componentWillUnmount if it is deleted.
* PR nits
We are using it with lazy and the combination Suspense + lazy seems pretty
stable. maxDuration is not but that's only enabled when you're in
ConcurrentMode which is still unstable.
Found a bug related to suspending inside an already mounted tree. While
investigating this I noticed we really don't have much coverage of
suspended updates. I think this would greatly benefit from some fuzz
testing; still haven't thought of a good test case, though.
* Add support for React.pure in ReactDOMServer
* Unwrap pure wrappers by creating an additional element as a single child
This is very slow but meh. We're rewriting this whole thing anyway.
* Allow arbitrary types to be wrapped in pure
This creates an outer fiber that container the pure check and an inner
fiber that represents which ever type of component.
* Add optimized fast path for simple pure function components
Special cased when there are no defaultProps and it's a simple function
component instead of class. This doesn't require an extra fiber.
We could make it so that this also works with custom comparer but that
means we have to go through one extra indirection to get to it.
Maybe it's worth it, donno.
* Introduce elementType field
This will be used to store the wrapped type of an element. E.g. pure and
lazy.
The existing type field will be used for the unwrapped type within them.
* Store the unwrapped type on the type field of lazy components
* Use the raw tags for lazy components
Instead, we check if the elementType and type are equal to test if
we need to resolve props. This is slightly slower in the normal case
but will yield less code and branching.
* Clean up lazy branches
* Collapse work tag numbering
* Split IndeterminateComponent out from Lazy
This way we don't have to check the type in a hacky way in the
indeterminate path. Also, lets us deal with lazy that resolves to
indeterminate and such.
* Missing clean up in rebase
* Always bail out timed out children even if they receive an update
The fragment that wraps timed-out children should always have an
expiration time of NoWork.
* Don't need to set expirationTime, only childExpirationTime
* Move memoizedProps to after beginWork remove memoizeProps helper
We always call this at the end. This is now enforced to line up since
we do the equality check in the beginning of beginWork. So we can't
have special cases.
* Inline the one caller of memoizeState
Outside of concurrent mode, schedules a force update on a suspended
class component to force it to prevent it from bailing out and
reusing the current fiber, which we know to be inconsistent.
Removes support for using arbitrary promises as the type of a React
element. Instead, promises must be wrapped in React.lazy. This gives us
flexibility later if we need to change the protocol.
The reason is that promises do not provide a way to call their
constructor multiple times. For example:
const promiseForA = new Promise(resolve => {
fetchA(a => resolve(a));
});
Given a reference to `promiseForA`, there's no way to call `fetchA`
again. Calling `then` on the promise doesn't run the constructor again;
it only attaches another listener.
In the future we will likely introduce an API like `React.eager` that
is similar to `lazy` but eagerly calls the constructor. That gives us
the ability to call the constructor multiple times. E.g. to increase
the priority, or to retry if the first operation failed.
* Suspense component does not capture if `fallback` is not defined
A missing fallback prop means the exception should propagate to the next
parent (like a rethrow). That way a Suspense component can specify other
props like maxDuration without needing to provide a fallback, too.
Closes#13864
* Change order of checks
This was the original, lower-level API before we landed on `fallback`
instead. (We might add a different lower-level API in the future, likely
alongside a new API for catching errors).
In the default mode, Suspense has special semantics where, in
addition to timing out immediately, we don't unwind the stack before
rendering the fallback. Instead, we commit the tree in an inconsistent
state, then synchronous render *again* to switch to the fallback. This
is slower but is less likely to cause issues with older components that
perform side effects in the render phase (e.g. componentWillMount,
componentWillUpdate, and componentWillReceiveProps).
We should do this in strict mode, too, so that there are no semantic
differences (in prod, at least) between default mode and strict mode.
The rationale is that it makes it easier to wrap a tree in strict mode
and start migrating components incrementally without worrying about new
bugs in production.
* Store the start time on `updateQueue` instead of `stateNode`
Originally I did this to free the `stateNode` field to store a second
set of children. I don't we'll need this anymore, since we use fragment
fibers instead. But I still think using `updateQueue` makes more sense
so I'll leave this in.
* Use fragment fibers to keep the primary and fallback children separate
If the children timeout, we switch to showing the fallback children in
place of the "primary" children. However, we don't want to delete the
primary children because then their state will be lost (both the React
state and the host state, e.g. uncontrolled form inputs). Instead we
keep them mounted and hide them. Both the fallback children AND the
primary children are rendered at the same time. Once the primary
children are un-suspended, we can delete the fallback children — don't
need to preserve their state.
The two sets of children are siblings in the host environment, but
semantically, for purposes of reconciliation, they are two separate
sets. So we store them using two fragment fibers.
However, we want to avoid allocating extra fibers for every placeholder.
They're only necessary when the children time out, because that's the
only time when both sets are mounted.
So, the extra fragment fibers are only used if the children time out.
Otherwise, we render the primary children directly. This requires some
custom reconciliation logic to preserve the state of the primary
children. It's essentially a very basic form of re-parenting.
* Use `memoizedState` to store various pieces of SuspenseComponent's state
SuspenseComponent has three pieces of state:
- alreadyCaptured: Whether a component in the child subtree already
suspended. If true, subsequent suspends should bubble up to the
next boundary.
- didTimeout: Whether the boundary renders the primary or fallback
children. This is separate from `alreadyCaptured` because outside of
strict mode, when a boundary times out, the first commit renders the
primary children in an incomplete state, then performs a second commit
to switch the fallback. In that first commit, `alreadyCaptured` is
false and `didTimeout` is true.
- timedOutAt: The time at which the boundary timed out. This is separate
from `didTimeout` because it's not set unless the boundary
actually commits.
These were previously spread across several fields.
This happens to make the non-strict case a bit less hacky; the logic for
that special case is now mostly localized to the UnwindWork module.
* Hide timed-out Suspense children
When a subtree takes too long to load, we swap its contents out for
a fallback to unblock the rest of the tree. Because we don't want
to lose the state of the timed out view, we shouldn't actually delete
the nodes from the tree. Instead, we'll keep them mounted and hide
them visually. When the subtree is unblocked, we un-hide it, having
preserved the existing state.
Adds additional host config methods. For mutation mode:
- hideInstance
- hideTextInstance
- unhideInstance
- unhideTextInstance
For persistent mode:
- cloneHiddenInstance
- cloneUnhiddenInstance
- createHiddenTextInstance
I've only implemented the new methods in the noop and test renderers.
I'll implement them in the other renderers in subsequent commits.
* Include `hidden` prop in noop renderer's output
This will be used in subsequent commits to test that timed-out children
are properly hidden.
Also adds getChildrenAsJSX() method as an alternative to using
getChildren(). (Ideally all our tests would use test renderer #oneday.)
* Implement hide/unhide host config methods for DOM renderer
For DOM nodes, we hide using `el.style.display = 'none'`.
Text nodes don't have style, so we hide using `text.textContent = ''`.
* Implement hide/unhide host config methods for Art renderer
* Create DOM fixture that tests state preservation of timed out content
* Account for class components that suspend outside concurrent mode
Need to distinguish mount from update. An unfortunate edge case :(
* Fork appendAllChildren between persistent and mutation mode
* Remove redundant check for existence of el.style
* Schedule placement effect on indeterminate components
In non-concurrent mode, indeterminate fibers may commit in an
inconsistent state. But when they update, we should throw out the
old fiber and start fresh. Which means the new fiber needs a
placement effect.
* Pass null instead of current everywhere in mountIndeterminateComponent
* Deprecate findDOMNode in StrictMode
There are two scenarios. One is that we pass a component instance that is
already in strict mode or the node that we find is in strict mode if
an outer component renders into strict mode.
I use a separate method findHostInstanceWithWarning for this so that
a) I can pass the method name (findDOMNode/findNodeHandle).
b) Can ignore this warning in React Native mixins/NativeComponent that use this helper.
I don't want to expose the fiber to the renderers themselves.
- "Interactive" -> "user-blocking"
- "Whenever" -> "Idle"
These are the terms used by @spanicker in their main-thread scheduling
proposal: https://github.com/spanicker/main-thread-scheduling#api-sketch
That proposal also uses "microtask" instead of "immediate" and "default"
instead of "normal." Not sure about "microtask" because I don't think
most people know what that is. And our implementation isn't a proper
microtask, though you could use it to implement microtasks if you made
sure to wrap every entry point. I don't really have a preference between
"default" and "normal."
These aren't necessarily the final names. Still prefixed by `unstable_`.
We're not planning to encourage legacy context, and without this change, it's difficult to use pure+forwardRef together. We could special-case `pure(forwardRef(...))` but this is hopefully simpler.
```js
React.pure(function(props, ref) {
// ...
});
```
Fixes#13777
As part of #11927 we introduced a regression by adding onclick handler
to the React root. This causes the whole React tree to flash when tapped
on iOS devices (for reasons I outlined in
https://github.com/facebook/react/issues/12989#issuecomment-414266839).
To fix this, we should only apply onclick listeners to portal roots. I
verified that my proposed fix indeed works by checking out our DOM
fixtures and adding regression tests.
Strangely, I had to make changes to the DOM fixtures to see the behavior
in the first place. This seems to be caused by our normal sites (and
thus their React root) being bigger than the viewport:

An alternative approach to finding out if we're appending to a React
root would be to add a third parameter to `appendChildToContainer` based
on the tag of the parent fiber.
* [scheduler] Eagerly schedule rAF at beginning of frame
Eagerly schedule the next animation callback at the beginning of the
frame. If the scheduler queue is not empty at the end of the frame, it
will continue flushing inside that callback. If the queue *is* empty,
then it will exit immediately. Posting the callback at the start of the
frame ensures it's fired within the earliest possible frame. If we
waited until the end of the frame to post the callback, we risk the
browser skipping a frame and not firing the callback until the frame
after that.
* Re-name scheduledCallback -> scheduledHostCallback
Previously, we were emptying root.pendingInteractionMap and permanently losing those interactions when applying an unrelated update to a tree that has no scheduled work that is waiting on promise resolution. (That is, one that is showing a fallback and waiting for the suspended content to resolve.)
The logic I'm leaving untouched with `nextRenderIncludesTimedOutPlaceholder` is *not* correct -- what we want is instead to know if *any* placeholder anywhere in the tree is showing its fallback -- but we don't currently have a better replacement, and this should unblock tracing with suspense again.
This package uses `process.env.NODE_ENV` but does not transform its usage during bundling like the rest of the React libraries do. This causes issues when `process` is not defined globally.
* Jest + test renderer helpers for concurrent mode
Most of our concurrent React tests use the noop renderer. But most
of those tests don't test the renderer API, and could instead be
written with the test renderer. We should switch to using the test
renderer whenever possible, because that's what we expect product devs
and library authors to do. If test renderer is sufficient for writing
most React core tests, it should be sufficient for others, too. (The
converse isn't true but we should aim to dogfood test renderer as much
as possible.)
This PR adds a new package, jest-react (thanks @cpojer). I've moved
our existing Jest matchers into that package and added some new ones.
I'm not expecting to figure out the final API in this PR. My goal is
to land something good enough that we can start dogfooding in www.
TODO: Continue migrating Suspense tests, decide on better API names
* Add additional invariants to prevent common errors
- Errors if user attempts to flush when log of yields is not empty
- Throws if argument passed to toClearYields is not ReactTestRenderer
* Better method names
- toFlushAll -> toFlushAndYield
- toFlushAndYieldThrough ->
- toClearYields -> toHaveYielded
Also added toFlushWithoutYielding
* Fix jest-react exports
* Tweak README
`--save` is on by default as of [npm 5](https://blog.npmjs.org/post/161081169345/v500), and `npm install aphrodite` is functionally equivalent to `npm install --save aphrodite` now
* Removed the enableGetDerivedStateFromCatch feature flag (aka permanently enabled the feature)
* Forked/copied ReactErrorBoundaries to ReactLegacyErrorBoundaries for testing componentDidCatch
* Updated error boundaries tests to apply to getDerivedStateFromCatch
* Renamed getDerivedStateFromCatch -> getDerivedStateFromError
* Warn if boundary with only componentDidCatch swallows error
* Fixed a subtle reconciliation bug with render phase error boundary
* pure
A higher-order component version of the `React.PureComponent` class.
During an update, the previous props are compared to the new props. If
they are the same, React will skip rendering the component and
its children.
Unlike userspace implementations, `pure` will not add an additional
fiber to the tree.
The first argument must be a functional component; it does not work
with classes.
`pure` uses shallow comparison by default, like `React.PureComponent`.
A custom comparison can be passed as the second argument.
Co-authored-by: Andrew Clark <acdlite@fb.com>
Co-authored-by: Sophie Alpert <sophiebits@fb.com>
* Warn if first argument is not a functional component
Added some tests for the non-DOM version of Scheduler that is used
as a fallback, e.g. Jest. The tests use Jest's fake timers API:
- `jest.runAllTimers(ms)` flushes all scheduled work, as expected
- `jest.advanceTimersByTime(ms)` flushes only callbacks that expire
within the given milliseconds.
These capabilities should be sufficient for most product tests. Because
jest's fake timers do not override performance.now or Date.now, we
assume time is constant. This means Scheduler's internal time will not
be aligned with other code that reads from `performance.now`. For finer
control, the user can override `window._sched` like we do in our tests.
We will likely publish a Jest package that has this built in.
All of these features are based on features of React's internal
scheduler. The eventual goal is to lift as much as possible out of the
React internals into the Scheduler package.
Includes some renaming of existing methods.
- `scheduleWork` is now `scheduleCallback`
- `cancelScheduledWork` is now `cancelCallback`
Priority levels
---------------
Adds the ability to schedule callbacks at different priority levels.
The current levels are (final names TBD):
- Immediate priority. Fires at the end of the outermost currently
executing (similar to a microtask).
- Interactive priority. Fires within a few hundred milliseconds. This
should only be used to provide quick feedback to the user as a result
of an interaction.
- Normal priority. This is the default. Fires within several seconds.
- "Maybe" priority. Only fires if there's nothing else to do. Used for
prerendering or warming a cache.
The priority is changed using `runWithPriority`:
```js
runWithPriority(InteractivePriority, () => {
scheduleCallback(callback);
});
```
Continuations
-------------
Adds the ability for a callback to yield without losing its place
in the queue, by returning a continuation. The continuation will have
the same expiration as the callback that yielded.
Wrapped callbacks
-----------------
Adds the ability to wrap a callback so that, when it is called, it
receives the priority of the current execution context.
* fix updateWrapper causing re-render textarea, even though their data has not changed
* fix updateWrapper causing re-render textarea, even though their data, prettier-all
* minor changes to updateWrapper, add test
* Do not bind topLevelType to dispatch
A previous change made it such that all top level event types
correspond to their associated native event string values. This commit
eliminates the .bind attached to dispatch and fixes a related flow
type.
* Add note about why casting event.type to a topLevelType is safe
* Move interactiveUpdates comment to point of assignment
* Refactor Schedule, remove React-isms
Once the API stabilizes, we will move Schedule this into a separate
repo. To promote adoption, especially by projects outside the React
ecosystem, we'll remove all React-isms from the source and keep it as
simple as possible:
- No build step.
- No static types.
- Everything is in a single file.
If we end up needing to support multiple targets, like CommonJS and ESM,
we can still avoid a build step by maintaining two copies of the same
file, but with different exports.
This commit also refactors the implementation to split out the DOM-
specific parts (essentially a requestIdleCallback polyfill). Aside from
the architectural benefits, this also makes it possible to write host-
agnostic tests. If/when we publish a version of Schedule that targets
other environments, like React Native, we can run these same tests
across all implementations.
* Edits in response to Dan's PR feedback
* Added UMD_PROFILING type to react-dom and scheduling package. Added UMD shim to schedule package.
* Added new schedule umd prod+prof bundle to API test
* Enhance dev warnings for forwardRef render function
- For 0 parameters: Do not warn because it may be due to usage of the
arguments object.
- For 1 parameter: Warn about missing the 'ref' parameter.
- For 2 parameters: This is the ideal. Do not warn.
- For more than 2 parameters: Warn about undefined parameters.
* Make test cases for forwardRef warnings more realistic
* Add period to warning sentence
* 🔥 Stop syncing the value attribute on inputs
* Eliminate some additional checks
* Remove initialValue and initialWrapper from wrapperState flow type
* Update tests with new sync logic, reduce some operations
* Update tests, add some caveats for SSR mismatches
* Revert newline change
* Remove unused type
* Call toString to safely type string values
* Add disableInputAttributeSyncing feature flag
Reverts tests to original state, adds attribute sync feature flag,
then moves all affected tests to ReactFire-test.js.
* Revert position of types in toStringValues
* Invert flag on number input blur
* Add clarification why double blur is necessary
* Update ReactFire number cases to be more explicite about blur
* Move comments to reduce diff size
* Add comments to clarify behavior in each branch
* There is no need to assign a different checked behavior in Fire
* Use checked reference
* Format
* Avoid precomputing stringable values
* Revert getToStringValue comment
* Revert placement of undefined in getToStringValue
* Do not eagerly stringify value
* Unify Fire test cases with normal ones
* Revert toString change. Only assign unsynced values when not nully
* Fix warning without stack for ie9
Where console methods like log, error etc. don't have 'apply' method.
Because of the lot of tests already expect that exactly console['method']
will be called - had to reapply references for console.error method
https://github.com/facebook/react/issues/13610
* pass parameters explicitly to avoid using .apply
which is not supported for console methods in ie9
* Minor tweaks
* add failing test
* honor displayName set on ForwardRef if available
Since React.forwardRef returns a component object, some users
(including styled-components and react-native) are starting to
decorate them with various statics including displayName.
This adjusts React's various name-getters to honor this if set and
surface the name in warnings and hopefully DevTools.
* fix typing
* Refine later
* Add home component. Async load fixtures.
This commit adds a homepage to the DOM fixtures that includes browser
testing information and asynchronously loads fixtures.
This should make it easier to find DOM testing information and keep
the payload size in check as we add more components to the fixtures.
* Adds experimental hydration fixture
This commit adds a first pass at a fixture that makes it easier to
debug the process of hydrating static markup. This is not complete:
1. It needs to be verified across multiple browsers
2. It needs to render with the current version of react
Still, it at least demonstrates the idea. A fixture like this will
also be helpful for debugging change events for hydrated inputs, which
presently do not fire if the user changes an input's text before
hydration.
* Tweak select width
* Manually join extra attributes in warning
This prevents a bug where Chrome reports `Array(n)` where `n` is the
size of the array.
* Transform with buble
* Eliminate dependencies
* Pull in react-live for better editing
* Handle encoding errors, pass react version
* Load the correct version of React
* Tweaks
* Revert style change
* Revert warning update
* Properly handle script errors. Fix dom-server CDN loading
* Fix 15.x releases
* Use postMessage to reduce latency, support older browsers
This commit makes a few tweaks to support older browsers and updates
the code transition process to use window.postMessage. This avoids
loading React on every single change.
* Fix fixture renamespacing bug
* Gracefully fallback to textarea in React 14
* Replace buble with babel, react-live with codemirror
* Simplify layout to resolve production code-mirror issues
* Tweak height rules for code-mirror
* Update theme to paraiso
* Format Code.js
* Adjust viewport to fix CodeMirror resize issue in production build
* Eliminate react-code-mirror
* Improve error state. Make full stack collapsable
* Add link to license in codemirror stylesheet
* Make code example more concise
* Replace "Hydrate" with "Auto-hydrate" for clarity
* Remove border below hydration header
* Rename query function in render.js
* Use Function(code) to evaluate hydration fixture
For clarity, and so that the Fixture component does not need to be
assigned to the window, this commit changes the way code is executed
such that it evaluates using a Function constructor.
* Extend hydration fixture to fill width. Design adjustments
This commit extends the hydration fixture such that it takes up the
full screen view. To accomplish this, the container that wraps all
fixtures has been moved to the FixtureSet component, utilized by all
other fixtures.
* Improve error scroll state
* Lazy load CodeMirror together before executing
This commit fixes an issue where CodeMirror wouldn't layout correctly
in production builds because the editor executes before the stylesheet
loaded. CodeMirror needs layout information, and was rendering
off-screen without correct CSS layout measurements.
* Fix indentation on error message
* Do not highlight errors from Babel. Add setPrototypeOf polyfill
This commit fixes an error in Safari 7.1 where Chalk highlighted Babel
errors caused a crash when setPrototypeOf was called within the
library.
This is also an issue on IE9, however this fix does not resolve issues
in that browser.
* Increase resilience to bad errors in Hydration fixture
- Reverts highlighting change. Polyfilling Safari 7.1 is sufficient
- Do not render a details tag in IE9
* Add regression test for persistent bailout bug
* Fork more logic into updateHostComponent
This is mostly copy paste. But I added a bailout only to mutation mode. Persistent mode doesn't have that props equality bailout anymore, so the Fabric test now passes.
* Add failing test for persistence host minimalism
* Add bailouts to the persistent host updates
* Added blessed production+profiling entry point for schedule/tracking
* Add invariant when profiling renderer is used with non-profiling schedule/tracking
* Remove injectComponentTree from unstable-native-dependencies, add
EventPluginHub
injectComponentTree was exposed for react-native-web, but wasn't
actually being used by the project. They were using EventPluginHub
through ReactDOM's secret internals, but that was removed in https://github.com/facebook/react/pull/13539
This removes the unused injectComponentTree export, refactors the
ResponderEventPlugin test so it doesn't depend on it, and also adds
EventPluginHub to the exports to unbreak react-native-web
* Re-export injectEventPluginsByName from ReactDOM internals
In https://github.com/facebook/react/pull/13394, I encountered an
issue where the ReactDOMServerIntegrationForm test suite consumed
sufficient memory to crash CircleCI. Breaking up this test suite by
form element type resolved the issue.
This commit performs that change separate from the Symbol/Function
stringification changes in #13394.
* Removed 'private' ref methods from UMD forwarding API
* Replaced getters with exported constants since they were no longer referenced for UMD forwarding
IE 11 parses & normalizes the style attribute as opposed to other
browsers. It adds spaces and sorts the properties in some
non-alphabetical order. Handling that would require sorting CSS
properties in the client & server versions or applying
`expectedStyle` to a temporary DOM node to read its `style` attribute
normalized. Since it only affects IE, we're skipping style warnings
in that browser completely in favor of doing all that work.
Fixes#11807
This is documenting the current order in which events are dispatched
when interacting with native document listeners and other React apps.
For more context, check out #12919.
* Merged interaction-tracking package into react-scheduler
* Add tracking API to FB+www builds
* Added Rollup plugin to strip no-side-effect imports from Rollup bundles
* Re-bundle tracking and scheduling APIs on SECRET_INTERNALS object for UMD build (and provide lazy forwarding methods)
* Added some additional tests and fixtures
* Fixed broken UMD fixture in master (#13512)
* Updated suspense fixture to use new interaction-tracking API
* Integrated Profiler API with interaction-tracking API (and added tests)
* Pass interaction Set (rather than Array) to Profiler onRender callback
* Removed some :any casts for enableInteractionTracking fields in FiberRoot type
* Refactored threadID calculation into a helper method
* Errors thrown by interaction tracking hooks use unhandledError to rethrow more safely.
Reverted try/finally change to ReactTestRendererScheduling
* Added a $FlowFixMe above the FiberRoot :any cast
* Reduce overhead from calling work-started hook
* Remove interaction-tracking wrap() references from unwind work in favor of managing suspense/interaction continuations in the scheduler
* Moved the logic for calling work-started hook from performWorkOnRoot() to renderRoot()
* Add interaction-tracking to bundle externals. Set feature flag to __PROFILE__
* Renamed the freezeInteractionCount flag and replaced one use-case with a method param
* let -> const
* Updated suspense fixture to handle recent API changes
* Add a failing test for deferredUpdates not being respected
* Don't consider deferred updates interactive
* Remove now-unnecessary setTimeout hack in the fixture
* Remove unstable_deferredUpdates
* Remove addEventListener check in isEventSupported
All browsers we support also support addEventListener, so this check is
unncessary
* Remove capture argument from isEventSupported
There's no good reason for this to be an object. This refactors it so
that we just use three variables instead. We can avoid the property reads/writes and also minify better, since property names don't get mangled but variables do.
* Do not toLowerCase lists of lowercase words
* Add notes about downcasing to DOMProperty.js
* Use consistent comment breakout
* Make toLowerCase more obvious
* Removed enableInteractionTrackingObserver as a separate flag; only enableInteractionTracking is used now
* Added interaction-tracking/subscriptions bundle and split tests
* Added multi-subscriber support
* Moved subscriptions behind feature flag
* Fixed bug with wrap() parameters and added test
* Replaced wrap arrow function
* Replace some namespace imports
* Simplify the controlled component injection
* Simplify the batching injection
* Simplify the component tree injection
* Add a regression test for 12643#issuecomment-413727104
* Don't diff memoized host components
* Add regression tests for noop renderer
* No early return
* Strengthen the test for host siblings
* Flow types
Lazily starts loading a component the first time it's rendered. The
implementation is fairly simple and could be left to userspace, but since
this is an important use case, there's value in standardization.
* Accept promise as element type
On the initial render, the element will suspend as if a promise were
thrown from inside the body of the unresolved component. Siblings should
continue rendering and if the parent is a Placeholder, the promise
should be captured by that Placeholder.
When the promise resolves, rendering resumes. If the resolved value
has a `default` property, it is assumed to be the default export of
an ES module, and we use that as the component type. If it does not have
a `default` property, we use the resolved value itself.
The resolved value is stored as an expando on the promise/thenable.
* Use special types of work for lazy components
Because reconciliation is a hot path, this adds ClassComponentLazy,
FunctionalComponentLazy, and ForwardRefLazy as special types of work.
The other types are not supported, but wouldn't be placed into a
separate module regardless.
* Resolve defaultProps for lazy types
* Remove some calls to isContextProvider
isContextProvider checks the fiber tag, but it's typically called after
we've already refined the type of work. We should get rid of it. I
removed some of them in the previous commit, and deleted a few more
in this one. I left a few behind because the remaining ones would
require additional refactoring that feels outside the scope of this PR.
* Remove getLazyComponentTypeIfResolved
* Return baseProps instead of null
The caller compares the result to baseProps to see if anything changed.
* Avoid redundant checks by inlining getFiberTagFromObjectType
* Move tag resolution to ReactFiber module
* Pass next props to update* functions
We should do this with all types of work in the future.
* Refine component type before pushing/popping context
Removes unnecessary checks.
* Replace all occurrences of _reactResult with helper
* Move shared thenable logic to `shared` package
* Check type of wrapper object before resolving to `default` export
* Return resolved tag instead of reassigning
* fix: do not reconcile children that are iterable functions
* fix: remove fit
* Refactor comparison to exclude anything that isnt an object
* Remove redundant undefined check
* Don't stop context traversal at matching consumers
Originally, the idea was to time slice the traversal. This worked when
there was only a single context type per consumer.
Now that each fiber may have a list of context dependencies, including
duplicate entries, that optimization no longer makes sense – we could
end up scanning the same subtree multiple times.
* Remove changedBits from context object and stack
Don't need it anymore, yay
Before this change in development window.event was overridden
in invokeGuardedCallback.
After this change window.event is preserved in the browsers that
support it.
* Warn when the string "false" is the value of a boolean DOM prop
* Only warn on exact case match for "false" in DOM boolean props
* Warn on string "true" as well as "false" in DOM boolean props
* Clarify warnings on "true" / "false" values in DOM boolean props
`flow-coverage-report` stopped working after Flow was set to run for each renderer separately (#12846). As discussed in #13393, this is hard to fix without adding complexity to `.flowconfig`'s generation.
* wip: ignore symbols and functions in select tag
* fix: Use ToStringValue as a maybe type
* refactor: remove unnecessary test
* refactor: remove implicit return from tests
* Add home component. Async load fixtures.
This commit adds a homepage to the DOM fixtures that includes browser
testing information and asynchronously loads fixtures.
This should make it easier to find DOM testing information and keep
the payload size in check as we add more components to the fixtures.
* Update browser support fields
* Tweak select width
* Fix typo
* Report actual error when fixture fails to load
* Update browser information
* Update browserstack subscription info
* English
* Switch let for const in fixture loader
* refactor: move getSafeValue to separate file
* fix(?): ReactDOMFiberTextarea sanitization for symbols and functions
* tests: add TODOs for warnings
* fix: restore accidentally removed test
* fix: remove redundant logic for initialValue
* refactor: integrate SafeValue typings into textarea
* fix: restore stringified newValue for equality check
* fix: remove getSafeValue from hostProps
* refactor: SafeValue -> ToStringValue
* refactor: update TODO comment in test file
* refactor: no need to convert children to ToStringValue
* Manually join extra attributes in warning
This prevents a bug where Chrome reports `Array(n)` where `n` is the
size of the array.
* Prettier
* Stringify all %s replaced symbols in warning
* Eliminate extra string coercion
* Pass args through with spread, convert all arguments to strings
* Rename strings to stringArgs
* Remove e.suppressReactErrorLogging check before last resort throw
It's unnecessary here. It was here because this method called console.error().
But we now rethrow with a clean stack, and that's worth doing regardless of whether the logging is silenced.
* Don't print error addendum if 'error' event got preventDefault()
* Add fixtures
* Use an expando property instead of a WeakSet
* Make it a bit less fragile
* Clarify comments
Following up on the changes I made in #13367, @gaearon suggest that
"safe" could be read as necessary for security. To avoid misleading a
reader, I'm changing the name.
A few names where discussed in the previous PR. I think `ToStringValue`
makes sense since the value itself is not a string yet but an opaque
type that can be cast to a string. For the actual string concatenation,
I've used `toString` now to avoid confusion: `toStringValueToString`
is super weird and it's namespaced anyhow.
Definitely open for suggestions here. :) I'll wait until we wrap up
#13362 and take care of rebase afterwards.
* Improve soundness of ReactDOMFiberInput typings
This is an attempt in improving the soundness for the safe value cast
that was added in #11741. We want this to avoid situations like [this
one](https://github.com/facebook/react/pull/13362#discussion_r209380079)
where we need to remember why we have certain type casts. Additionally
we can be sure that we only cast safe values to string.
The problem was `getSafeValue()`. It used the (deprecated) `*` type to
infer the type which resulted in a passing-through of the implicit `any`
of the props `Object`. So `getSafeValue()` was effectively returning
`any`.
Once I fixed this, I found out that Flow does not allow concatenating
all possible types to a string (e.g `"" + false` fails in Flow). To
fix this as well, I've opted into making the SafeValue type opaque and
added a function that can be used to get the string value. This is sound
because we know that SafeValue is already checked.
I've verified that the interim function is inlined by the compiler and
also looked at a diff of the compiled react-dom bundles to see if I've
regressed anything. Seems like we're good.
* Fix typo
* Bring back onSubmit bubble test
I found a test that was written more than 5 years ago and probably never
run until now. The behavior still works, although the API changed quite
a bit over the years.
Seems like this was part of the initial public release already:
75897c2dcd (diff-1bf5126edab96f3b7fea034cd3b0c742R31)
* Rely on bubbling for submit and reset events
* Update dom fixture lockfile
* Revet rollup results
Whoopsie.
* Simplified profiler actualDuration timing
While testing the new DevTools profiler, I noticed that sometimes– in larger, more complicated applications– the actualDuration value was incorrect (either too large, or sometimes negative). I was not able to reproduce this in a smaller application or test (which sucks) but I assume it has something to do with the way I was tracking render times across priorities/roots. So this PR replaces the previous approach with a simpler one.
* Changed bubbling logic after chatting out of band with Andrew
* Replaced __PROFILE__ with feature-flag conditionals in test
* Updated test comment
Remove 'async', 'bundle-collapser', 'del', 'derequire', 'escape-string-regexp', 'git-branch', 'gzip-js',
'merge-stream', 'platform', 'run-sequence' & 'yargs'.
Most of them were used in the old Grunt build system.
This ends up removing 32 packages, according to yarn.lock.
* Add support for auxclick event
* Add to simpleEventPLugin
* Add auxclick as interactive event type in SimpleEventPlugin
* Update ReactTestUtils fixture to include auxClick
* fix selectedIndex in postMountWrapper in ReactDOMFiberSelected
* comment in ReactDomFiberSelect in postMountWrapper for selectedIndex fix
* test for selectedIndex fix
* set boolean value for multiple
* Revert the fix which has been fixed on master
* Make sure that `select` has `multiple` attribute set to appropriate state before appending options
fixes#13222
* Add dom test fixture to test long multiple select scrolling to the first selected option
fixes#13222
* typo fix
* update comment
remove redundant conversion to bool type
* change a way of assigning property to domElement
* Remove unused ref on select fixture form
* Prefer node’s window and document over globals
* Support active elements in nested browsing contexts
* Avoid invoking defaultView getter unnecessarily
* Prefer node’s window and document over globals
* Support active elements in nested browsing contexts
* Avoid invoking defaultView getter unnecessarily
* Implement selection event fixtures
* Prefer node’s window and document over globals
* Avoid invoking defaultView getter unnecessarily
* Fix react-scripts to work with alphas after 16.0.0
The current logic just checks if the version is an alpha with a major version of 16 to account for weirdness with the 16 RC releases, but now we have alphas for newer minor releases that don't have weirdness
* Run prettier on new selection events fixtures
* Add fixture for onSelect in iframes, remove DraftJS fixture
The DraftJs fixture wasn't really working in all supported browsers anyways, so just drop it and try to cover our bases without using it directly
* Purge remnants of draft.js from fixtures
* Use prop-types import instead of window global
* Make fixtures’ Iframe component Firefox-compatible
* Fix switch case for SelectionEventsFixture
* Remove draft.js / immutable.js dependencies
* Cache owner doc as var to avoid reading it twice
* Add documentation for getActiveElementDeep to explain try/catch
Add documentation for getActiveElementDeep to explain try/catch
* Ensure getActiveElement always returns DOM element
* Tighten up isNode and isTextNode
* Remove ie8 compatibility
* Specify cross-origin example in getActiveElementDeep
* Revert back to returning null if document is not defined
* Add a regression test for #13188
* Replace console.error() with a throw in setTimeout() as last resort
* Fix lint and comment
* Fix tests to check we throw after all
* Fix build tests
* Inject react-art renderer into react-devtools
This commit makes react-art renderer to be injected to react-devtools,
so that component tree of the renderer is presented on debug panel of browser.
* Update ReactART.js
* [#13130] Add a more helpful message when passing an element to createElement()
* better conditional flow
* update after review
* move last condition inside last else clause
* Added test case
* compare 25132typeof to REACT_ELEMENT_TYPE
* runs prettier
* remove unrelated changes
* Tweak the message
* Make option children a text content by default
fix#11911
* Apply requested changes
- Remove meaningless comments
- revert scripts/rollup/results.json
* remove empty row
* Update comment
* Add a simple unit-test
* [WIP: no flow] Pass through hostContext
* [WIP: no flow] Give better description for test
* Fixes
* Don't pass hostContext through
It ended up being more complicated than I thought.
* Also warn on hydration
* Remove 'warning' module from the JS scheduler
**what is the change?:**
See title
**why make this change?:**
Internally the 'warning' module has some dependencies which we want to
avoid pulling in during the very early stages of initial pageload. It is
creating a cyclical dependency.
And we wanted to remove this dependency anyway, because this module
should be kept small and decoupled.
**test plan:**
- Tested the exact same change internally in Facebook.com
- Ran unit tests
- Tried out the fixture
**issue:**
Internal task T31831021
* check for console existence before calling console.error
* Move DEV check into separate block
This is likely the common case because individual component authors
will casually call read on common contexts like the cache, or cache
provider.
Where as libraries like Relay only call read once per fragment and pass
all observed bits at once.
* Store list of contexts on the fiber
Currently, context can only be read by a special type of component,
ContextConsumer. We want to add support to all fibers, including
classes and functional components.
Each fiber may read from one or more contexts. To enable quick, mono-
morphic access of this list, we'll store them on a fiber property.
* Context.unstable_read
unstable_read can be called anywhere within the render phase. That
includes the render method, getDerivedStateFromProps, constructors,
functional components, and context consumer render props.
If it's called outside the render phase, an error is thrown.
* Remove vestigial context cursor
Wasn't being used.
* Split fiber.expirationTime into two separate fields
Currently, the `expirationTime` field represents the pending work of
both the fiber itself — including new props, state, and context — and of
any updates in that fiber's subtree.
This commit adds a second field called `childExpirationTime`. Now
`expirationTime` only represents the pending work of the fiber itself.
The subtree's pending work is represented by `childExpirationTime`.
The biggest advantage is it requires fewer checks to bailout on already
finished work. For most types of work, if the `expirationTime` does not
match the render expiration time, we can bailout immediately without
any further checks. This won't work for fibers that have
`shouldComponentUpdate` semantics (class components), for which we still
need to check for props and state changes explicitly.
* Performance nits
Optimize `readContext` for most common case
* Add a test that StrictMode shows up in the component stack
The SSR test passes. The client one doesn't.
* Include Modes in component stack
* Update other tests to include modes
Adds custom Jest matchers that help with writing async tests:
- `toFlushThrough`
- `toFlushAll`
- `toFlushAndThrow`
- `toClearYields`
Each one accepts an array of expected yielded values, to prevent
false negatives.
Eventually I imagine we'll want to publish this on npm.
* Add a repro case for profiler unwinding
This currently fails the tests due to an unexpected warning.
* Add a regression test for context stack
* Simplify the first test case
* Update nextUnitOfWork inside completeUnitOfWork()
The bug was caused by a structure like this:
</Provider>
</div>
</errorInCompletePhase>
We forgot to update nextUnitOfWork so it was still pointing at Provider when errorInCompletePhase threw. As a result, we would try to unwind from Provider (rather than from errorInCompletePhase), and thus pop the Provider twice.
The `yield` method isn't tied to any specific root. Putting this
on the main export enables test components that are not within scope
to yield even if they don't have access to the currently rendering
root instance. This follows the pattern established by ReactNoop.
Added a `clearYields` method, too, for reading values that were yielded
out of band. This is also based on ReactNoop.
* Revert #5947 and disable the test
* Fix isDefaultPrevented and isPropagationStopped to not get nulled
This was a bug introduced by #5947. It's very confusing that they become nulled while stopPropagation/preventDefault don't.
* Add a comment
* Run Prettier
* Fix grammar
* Fix Portal unmount
Before that change, currentParent is not set as a container even if it should so it break on react-native and probably other custom renderers
* Assert that *ToContainer() methods receive containers
* Add regression tests
* Add comments
This is a leftover from #13161 that I forgot to include.
It ensures we don't accidentally write code in the old way and end up passing the stack twice.
* Use %s in the console calls
* Add shared/warningWithStack
* Convert some warning callsites to warningWithStack
* Use warningInStack in shared utilities and remove unnecessary checks
* Replace more warning() calls with warningWithStack()
* Fixes after rebase + use warningWithStack in react
* Make warning have stack by default; warningWithoutStack opts out
* Forbid builds that may not use internals
* Revert newly added stacks
I changed my mind and want to keep this PR without functional changes. So we won't "fix" any warnings that are already missing stacks. We'll do it in follow-ups instead.
* Fix silly find/replace mistake
* Reorder imports
* Add protection against warning argument count mismatches
* Address review
* Suspending inside a constructor outside of strict mode
Outside of strict mode, suspended components commit in an incomplete
state, then are synchronously deleted in a subsequent commit. If a
component suspends inside the constructor, it mounts without
an instance.
This breaks at least one invariant: during deletion, we assume that
every mounted component has an instance, and check the instance for
the existence of `componentWillUnmount`.
Rather than add a redundant check to the deletion of every class
component, components that suspend inside their constructor and outside
of strict mode are turned into empty functional components before they
are mounted. This is a bit weird, but it's an edge case, and the empty
component will be synchronously unmounted regardless.
* Do not fire lifecycles of a suspended component
In non-strict mode, suspended components commit, but their lifecycles
should not fire.
Instead of wrapping ReactDebugCurrentFrame.getStackAddendum() call into a custom wrapper inside ReactElementValidator, "teach" the main ReactDebugCurrentFrame.getStackAddendum() to take currently validating element into account.
* Fix getComponentName() for types with nested $$typeof
* Temporarily remove Profiler ID from messages
* Change getComponentName() signature to take just type
It doesn't actually need the whole Fiber.
* Remove getComponentName() forks in isomorphic and SSR
* Remove unnecessary .type access where we already have a type
* Remove unused type
* Remove event simulation of onChange events
It’s time to get rid of even more `ReactTestUtils.Simulate`s. In this PR
we remove the event simulation from all onChange tests. To do this, we
have to get a setter to the untracked value/checked props.
All remaining `ReactTestUtils.Simulate` calls are either testing
ReactTestUtils or assert that they do/don't throw.
* Use input instead of change event for all but checkbox, radio, and select
`React$ElementRef<T>` is the type of the ref _instance_ for a component of type T, whereas `React$Ref<T>` is the type of the ref _prop_ for a component of type T, which seems to be the intended type here.
* Refactor ReactDebugCurrentFiber to use named exports
This makes the difference between it and ReactFiberCurrentFrame a bit clearer.
ReactDebugCurrentFiber is Fiber's own implementation.
ReactFiberCurrentFrame is the thing that holds a reference to the current implementation and delegates to it.
* Unify ReactFiberComponentTreeHook and ReactDebugCurrentFiber
Conceptually they're very related.
ReactFiberComponentTreeHook contains implementation details of reading Fiber's stack (both in DEV and PROD).
ReactDebugCurrentFiber contained a reference to the current fiber, and used the above utility.
It was confusing when to use which one. Colocating them makes it clearer what you could do with each method.
In the future, the plan is to stop using these methods explicitly in most places, and instead delegate to a warning system that includes stacks automatically. This change makes future refactorings simpler by colocating related logic.
* Rename methods to better reflect their meanings
Clarify which are DEV or PROD-only.
Clarify which can return null.
I believe the "work in progress only" was a mistake. I introduced it because I wasn't sure what guarantees we have around .return. But we know for sure that following a .return chain gives us an accurate stack even if we get into WIP trees because we don't have reparenting. So it's fine to relax that naming.
* Rename ReactDebugCurrentFiber -> ReactCurrentFiber
It's not completely DEV-only anymore.
Individual methods already specify whether they work in DEV or PROD in their names.
An infinite update loop can occur when an update is scheduled inside a
lifecycle method, which causes a re-render, which schedules another
update, and so on. Before the Fiber rewrite, this scenario resulted in a
stack overflow.
Because Fiber does not use the JavaScript stack, we maintain our own
counter to track the number of nested, synchronous updates. We throw an
error if the limit is exceeded.
The nested update limit is currently 1000. I chose this number
arbitrarily, certain that there was no valid reason for a component to
schedule so many synchronous re-renders.
I think we can go much lower. This commit decreases the limit to 50. I
believe this is still comfortably above the reasonable number of
synchronous re-renders a component may perform.
This will make it easier for developers to debug infinite update bugs
when they occur.
A recent change to the scheduler caused a regression when scheduling
many updates within a single batch. Added a test case that would
have caught this.
This is an unobservable change to all but the (under development) DevTools Profiler plugin. It is being done so that the plugin can safely feature detect a version of React that supports it. The profiler API has existed since the 16.4.0 release, but it did not support the DevTools plugin prior to PR #13058.
Side note: I am not a big fan of the term "base duration". Both it and "actual duration" are kind of awkward and vague. If anyone has suggestions for better names– this is the best time to bikeshed about them.
* Reset ReactProfilerTimer's DEV-only Fiber stack after an error
* Added ReactNoop functionality to error during "complete" phase
* Added failing profiler stack unwinding test
* Potential fix for unwinding time bug
* Renamed test
* Don't record time until complete phase succeeds. Simplifies unwinding.
* Expanded ReactProfilerDevToolsIntegration-test coverage a bit
* Added unstable_flushWithoutCommitting method to noop renderer
* Added failing multi-root/batch test to ReactProfiler-test
* Beefed up tests a bit and added some TODOs
* Profiler timer differentiates between batched commits and in-progress async work
This was a two-part change:
1) Don't count time spent working on a batched commit against yielded async work.
2) Don't assert an empty stack after processing a batched commit (because there may be yielded async work)
This is kind of a hacky solution, and may have problems that I haven't thought of yet. I need to commit this so I can mentally clock out for a bit without worrying about it. I will think about it more when I'm back from PTO. In the meanwhile, input is welcome.
* Removed TODO
* Replaced FiberRoot map with boolean
* Removed unnecessary whitespace edit
Changed the API to match what we've been using in our latest discussions.
Our tentative plans are for <Placeholder> to automatically hide the timed-out
children, instead of removing them, so their state is not lost. This part is
not yet implemented. We'll likely have a lower level API that does not include
the hiding behavior. This is also not yet implemented.
We can support components that suspend outside of an async mode tree
by immediately committing their placeholders.
In strict mode, the Timeout acts effectively like an error boundary.
Within a single render pass, we unwind to the nearest Timeout and
re-render the placeholder view.
Outside of strict mode, it's not safe to unwind and re-render the
siblings without committing. (Technically, this is true of error
boundaries, too, though probably not a huge deal, since we don't support
using error boundaries for control flow (yet, at least)). We need to be
clever. What we do is pretend the suspended component rendered null.*
There's no unwinding. The siblings commit like normal.
Then, in the commit phase, schedule an update on the Timeout to
synchronously re-render the placeholder. Although this requires an extra
commit, it will not be observable. And because the siblings were not
blocked from committing, they don't have to be strict mode compatible.
Another caveat is that if a component suspends during an async render,
but it's captured by a non-async Timeout, we need to revert to sync
mode. In other words, if any non-async component renders, the entire
tree must complete and commit without yielding.
* The downside of rendering null is that the existing children will be
deleted. We should hide them instead. I'll work on this in a follow-up.
* Prepare placeholders before timing out
While a tree is suspended, prepare for the timeout by pre-rendering the
placeholder state.
This simplifies the implementation a bit because every render now
results in a completed tree.
* Suspend inside an already timed out Placeholder
A component should be able to suspend inside an already timed out
placeholder. The time at which the placeholder committed is used as
the start time for a subsequent suspend.
So, if a placeholder times out after 3 seconds, and an inner
placeholder has a threshold of 2 seconds, the inner placeholder will
not time out until 5 seconds total have elapsed.
* Fix crash during server render.
setTimeout and clearTimeout may not be available in some server-render environments (such as ChakraCore in React.NET), and loading ReactScheduler.js will cause a crash unless the existence of the variables are checked via a typeof comparison.
https://github.com/reactjs/React.NET/issues/555
The crash did not occur in 16.4.0, and the change appears to have been introduced here: https://github.com/facebook/react/pull/12931/files#diff-bbebc3357e1fb99ab13ad796e04b69a6L47
I tested this by using yarn link and running it with a local copy of React.NET. I am unsure the best way to unit test this change, since assigning null to `setTimeout` causes an immediate crash within the Node REPL.
* Fix flow errors and log warning if setTimeout / clearTimeout are
not defined / not a function.
* Use invariant to assert setTimeout / clearTimeout are functions
* Remove use of invariant
* Explain
* Add fixture test for schedule running when tab is backgrounded
**what is the change?:**
Just adding a test to the fixture, where we can easily see whether
scheduled callbacks are called after switching away from the fixture
tab.
**why make this change?:**
We are about to fix the schedule module so that it still runs even when
the tab is in the backround.
**test plan:**
Manually tested the fixture, verified that it works as expected and
right now callbacks are not called when the tab is in the background.
**issue:**
Internal task T30754186
* Fall back to 'setTimeout' when 'requestAnimationFrame' is not called
**what is the change?:**
If 'requestAnimationFrame' is not called for 100ms we fall back to
'setTimeout' to schedule the postmessage.
**why make this change?:**
When you start loading a page, and then switch tabs,
'requestAnimationFrame' is throttled or not called until you come back
to that tab. That means React's rendering, any any other scheduled work,
are paused.
Users expect the page to continue loading, and rendering is part of the
page load in a React app. So we need to continue calling callbacks.
**test plan:**
Manually tested using the new fixture test, observed that the callbacks
were called while switched to another tab. They were called more
slowly, but that seems like a reasonable thing.
**issue:**
Internal task T30754186
* make arguments more explicit
* Fixes children when using dangerouslySetInnerHtml in a selected <option>
This fixes an inadvertent cast of undefined children to an empty string when creating an option tag that will be selected:
```
<select defaultValue="test">
<option value='test' dangerouslySetInnerHTML={{ __html: '‏ test'}} />
</select>
```
This causes an invariant error because both children and dangerouslySetInnerHTML are set.
* PR fix and new ReactDOMServerIntegrationForms test
* Account for null case
* Combine test cases into single test
* Add tests for failure cases
* Fix lint
* react-test-renderer injects itself into DevTools if present
* Fibers are always opted into ProfileMode if DevTools is present
* Added simple test for DevTools + always profiling behavior
* Do not add additional work to a batch that is already rendering.
Otherwise, the part of the tree that hasn't rendered yet will receive
the latest state, but the already rendered part will show the state
as it was before the intervening update.
* Reduce non-helpfulness of comments
Expiration times are computed by adding to the current time (the start
time). However, if two updates are scheduled within the same event, we
should treat their start times as simultaneous, even if the actual clock
time has advanced between the first and second call.
In other words, because expiration times determine how updates are
batched, we want all updates of like priority that occur within the same
event to receive the same expiration time. Otherwise we get tearing.
We keep track of two separate times: the current "renderer" time and the
current "scheduler" time. The renderer time can be updated whenever; it
only exists to minimize the calls performance.now.
But the scheduler time can only be updated if there's no pending work,
or if we know for certain that we're not in the middle of an event.
* Inline fbjs/lib/emptyObject
* Explicit naming
* Compare to undefined
* Another approach for detecting whether we can mutate
Each renderer would have its own local LegacyRefsObject function.
While in general we don't want `instanceof`, here it lets us do a simple check: did *we* create the refs object?
Then we can mutate it.
If the check didn't pass, either we're attaching ref for the first time (so we know to use the constructor),
or (unlikely) we're attaching a ref to a component owned by another renderer. In this case, to avoid "losing"
refs, we assign them onto the new object. Even in that case it shouldn't "hop" between renderers anymore.
* Clearer naming
* Add test case for strings refs across renderers
* Use a shared empty object for refs by reading it from React
* Remove string refs from ReactART test
It's not currently possible to resetModules() between several renderers
without also resetting the `React` module. However, that leads to losing
the referential identity of the empty ref object, and thus subsequent
checks in the renderers for whether it is pooled fail (and cause assignments
to a frozen object).
This has always been the case, but we used to work around it by shimming
fbjs/lib/emptyObject in tests and preserving its referential identity.
This won't work anymore because we've inlined it. And preserving referential
identity of React itself wouldn't be great because it could be confusing during
testing (although we might want to revisit this in the future by moving its
stateful parts into a separate package).
For now, I'm removing string ref usage from this test because only this is
the only place in our tests where we hit this problem, and it's only
related to string refs, and not just ref mechanism in general.
* Simplify the condition
In async mode, events are interleaved with rendering. If one of those
events mutates state that is later accessed during render, it can lead
to inconsistencies/tearing.
Restarting the render from the root is often sufficient to fix the
inconsistency. We'll flush the restart synchronously to prevent yet
another mutation from happening during an interleaved event.
We'll only restart during an async render. Sync renders are already
sync, so there's no benefit in restarting. (Unless a mutation happens
during the render phase, but we don't support that.)
* onFatal, onComplete, onSuspend, onYield
For every call to renderRoot, one of onFatal, onComplete, onSuspend,
and onYield is called upon exiting. We use these in lieu of returning a
tuple. I've also chosen not to inline them into renderRoot because these
will eventually be lifted into the renderer.
* Suspended high pri work forces lower priority work to expire early
If an error is thrown, and there is lower priority pending work, we
retry at the lower priority. The lower priority work should expire
at the same time at which the high priority work would have expired.
Effectively, this increases the priority of the low priority work.
Simple example: If an error is thrown during a synchronous render, and
there's an async update, the async update should flush synchronously in
case it's able to fix the error. I've added a unit test for
this scenario.
User provided timeouts should have the same behavior, but I'll leave
that for a future PR.
* Add isUsingKoreanIME function to check if a composition event was triggered by Korean IME
* Add Korean IME check alongside useFallbackCompositionData and disable fallback mode with Korean IME
We need a different "component tree" thingy for Fabric.
A lot of this doesn't really make much sense in a persistent world but
currently we can't dispatch events to memoizedProps on a Fiber since
they're pooled. Also, it's unclear what the semantics should be when we
dispatch an event that happened when the old props were in effect but now
we have new props already.
This implementation tries to use the last committed props but also fails
at that because we don't have a commit hook in the persistent mode.
However, at least it doesn't crash when dispatching. :)
* Remove rAF fork
**what is the change?:**
Undid https://github.com/facebook/react/pull/12837
**why make this change?:**
We originally forked rAF because we needed to pull in a particular
version of rAF internally at Facebook, to avoid grabbing the default
polyfilled version.
The longer term solution, until we can get rid of the global polyfill
behavior, is to initialize 'schedule' before the polyfilling happens.
Now that we have landed and synced
https://github.com/facebook/react/pull/12900 successfully, we can
initialize 'schedule' before the polyfill runs.
So we can remove the rAF fork. Here is how it will work:
1. Land this PR on Github.
2. Flarnie will quickly run a sync getting this change into www.
3. We delete the internal forked version of
'requestAnimationFrameForReact'.
4. We require 'schedule' in the polyfill file itself, before the
polyfilling happens.
**test plan:**
Flarnie will manually try the above steps locally and verify that things
work.
**issue:**
Internal task T29442940
* fix nits
* fix tests, fix changes from rebasing
* fix lint
* Remove enableSuspense flag from PendingPriority module
We're going to use this for suspending on error, too.
* Retry on error if there's lower priority pending work
If an error is thrown, and there's lower priority work, it's possible
the lower priority work will fix the error. Retry at the lower priority.
If an error is thrown and there's no more work to try, handle the error
like we normally do (trigger the nearest error boundary).
* Use native event dispatching instead of Simulate or SimulateNative
In #12629 @gaearon suggested that it would be better to drop usage of
`ReactTestUtils.Simulate` and `ReactTestUtils.SimulateNative`. In this
PR I’m attempting at removing it from a lot of places with only a few
leftovers.
Those leftovers can be categorized into three groups:
1. Anything that tests that `SimulateNative` throws. This is a property
that native event dispatching doesn’t have so I can’t convert that
easily. Affected test suites: `EventPluginHub-test`,
`ReactBrowserEventEmitter-test`.
2. Anything that tests `ReactTestUtils` directly. Affected test suites:
`ReactBrowserEventEmitter-test` (this file has one test that reads
"should have mouse enter simulated by test utils"),
`ReactTestUtils-test`.
3. Anything that dispatches a `change` event. The reason here goes a bit
deeper and is rooted in the way we shim onChange. Usually when using
native event dispatching, you would set the node’s `.value` and then
dispatch the event. However inside [`inputValueTracking.js`][] we
install a setter on the node’s `.value` that will ignore the next
`change` event (I found [this][near-perfect-oninput-shim] article
from Sophie that explains that this is to avoid onChange when
updating the value via JavaScript).
All remaining usages of `Simulate` or `SimulateNative` can be avoided
by mounting the containers inside the `document` and dispatching native
events.
Here some remarks:
1. I’m using `Element#click()` instead of `dispatchEvent`. In the jsdom
changelog I read that `click()` now properly sets the correct values
(you can also verify it does the same thing by looking at the
[source][jsdom-source]).
2. I had to update jsdom in order to get `TouchEvent` constructors
working (and while doing so also updated jest). There was one
unexpected surprise: `ReactScheduler-test` was relying on not having
`window.performance` available. I’ve recreated the previous
environment by deleting this property from the global object.
3. I was a bit confused that `ReactTestUtils.renderIntoDocument()` does
not render into the document 🤷
[`inputValueTracking.js`]: 392530104c/packages/react-dom/src/client/inputValueTracking.js (L79)
[near-perfect-oninput-shim]: https://sophiebits.com/2013/06/18/a-near-perfect-oninput-shim-for-ie-8-and-9.html
[jsdom-source]: 45b77f5d21/lib/jsdom/living/nodes/HTMLElement-impl.js (L43-L76)
* Make sure contains are unlinked from the document even if the test fails
* Remove unnecessary findDOMNode calls
**what is the change?:**
Basically undoes 4b2e65d32e (diff-904ceabd8a1e9a07ab1d876d843d62e1)
**why make this change?:**
We rolled out this fix internally and in open source weeks ago, and now
we're cleaning up.
**test plan:**
Ran tests and lint, and really we have been testing this because the
flag is open internally as of last week or so.
**issue:**
Internal task T29948812 has some info.
* Don’t error when returning an empty Fragment
When a fragment is reconciled, we directly move onto it’s children.
Since an empty `<React.Fragment/>` will have children of `undefined`,
this would always throw.
To fix this, we bail out in those cases.
* Test the update path as well
* Reuse existing code path
* An even more explicit solution that also fixes Flow
It looks like we accidentally removed a fallback condition for the
event target in IE9 when we dropped some support for IE8. This commit
adds the event target specific support code back to getEventTarget.js
Fixes#12506
* Fixed an issue with nested contexts unwinding when server rendering. GitHub issue #12984
* Fixed an issue with search direction and stricter false checking
* Use decrement infix operator
* Streamlined existence checks
* Streamlined assignment. Removed redundant comment. Use null for array values
* Made prettier
* Relaxed type checking and improved comment
* Improve test coverage
This commit removes a reference to inst._wrapperState, which was the
old way of tracking input state in the stack renderer.
This means we no longer need to pass the instance into the associated
function, allowing us to eliminate an exception for IE (and a TODO).
* Fix react-dom ReferenceError requestAnimationFrame in non-browser env (#13000)
The https://github.com/facebook/react/pull/12931 ( 79a740c6e3 ) broke the server-side rendering: in the `fixtures/ssr` the following error appeared from the server-side when `localhost:3000` is requested:
```
ReferenceError: requestAnimationFrame is not defined
at /__CENSORED__/react/build/node_modules/react-dom/cjs/react-dom.development.js:5232:34
at Object.<anonymous> (/__CENSORED__/react/build/node_modules/react-dom/cjs/react-dom.development.js:17632:5)
at Module._compile (module.js:624:30)
at Module._extensions..js (module.js:635:10)
at Object.require.extensions.(anonymous function) [as .js] (/__CENSORED__/react/fixtures/ssr/node_modules/babel-register/lib/node.js:152:7)
at Module.load (module.js:545:32)
at tryModuleLoad (module.js:508:12)
at Function.Module._load (module.js:500:3)
at Module.require (module.js:568:17)
at require (internal/module.js:11:18)
```
The exception pointed to this line:
```js
// We capture a local reference to any global, in case it gets polyfilled after
// this module is initially evaluated.
// We want to be using a consistent implementation.
const localRequestAnimationFrame = requestAnimationFrame;
```
**Test plan**
1. In `react` repo root, `yarn && yarn build`.
2. In `fixtures/ssr`, `yarn && yarn start`,
3. In browser, go to `http://localhost:3000`.
4. Observe the fixture page, not the exception message.
* Move the requestAnimationFrameForReact check and warning to callsites (#13000)
According to the comment by @gaearon: https://github.com/facebook/react/pull/13001#issuecomment-395803076
* Use `invariant` instead of `throw new Error`, use the same message (#13000)
According to the comment by @gaearon: https://github.com/facebook/react/pull/13001#discussion_r194133355
* Set the correct initial value on input range
* Add description and update value diff check for input range
* add isHydrating argument and tests
* update node value according to isHydrating
* Initial failing unit test for error handling in schedule
**what is the change?:**
see title
**why make this change?:**
Adding tests for the error handling behavior we are about to add. This
test is failing, which gives us the chance to make it pass.
Wrote skeletons of some other tests to add.
Unit testing this way is really hacky, and I'm also adding to the
fixture to test this in the real browser environment.
**test plan:**
Ran new test, saw it fail!
* Add fixture for testing error handling in scheduler
**what is the change?:**
Added a fixture which does the following -
logs in the console to show what happens when you use
`requestAnimationFrame` to schedule a series of callbacks and some of
them throw errors.
Then does the same actions with the `scheduler` and verifies that it
behaves in a similar way.
Hard to really verify the errors get thrown at the proper time without
looking at the console.
**why make this change?:**
We want the most authentic, accurate test of how errors are handled in
the scheduler. That's what this fixture should be.
**test plan:**
Manually verified that this test does what I expect - right now it's
failing but follow up commits will fix that.
* Handle errors in scheduler
**what is the change?:**
We set a flag before calling any callback, and then use a 'try/finally'
block to wrap it. Note that we *do not* catch the error, if one is
thrown. But, we only unset the flag after the callback successfully
finishes.
If we reach the 'finally' block and the flag was not unset, then it
means an error was thrown.
In that case we start a new postMessage callback, to finish calling any
other pending callbacks if there is time.
**why make this change?:**
We need to make sure that an error thrown from one callback doesn't stop
other callbacks from firing, but we also don't want to catch or swallow
the error because we want engineers to still be able to log and debug
errors.
**test plan:**
New tests added are passing, and we verified that they fail without this
change.
* Add more tests for error handling in scheduler
**what is the change?:**
Added tests for more situations where error handling may come up.
**why make this change?:**
To get additional protection against this being broken in the future.
**test plan:**
Ran new tests and verified that they fail when error handling fails.
* callSafely -> callUnsafely
* Fix bugs with error handling in schedule
**what is the change?:**
- ensure that we properly remove the callback from the linked list, even
if it throws an error and is timed out.
- ensure that you can call 'cancelScheduledWork' more than once and it
is idempotent.
**why make this change?:**
To fix bugs :)
**test plan:**
Existing tests pass, and we'll add more tests in a follow up commit.
* Unit tests for error handling with timed out callbacks
**what is the change?:**
More unit tests, to cover behavior which we missed; error handling of
timed out callbacks.
**why make this change?:**
To protect the future!~
**test plan:**
Run the new tests.
* Adds fixture to test timed out callbacks with scheduler
**what is the change?:**
See title
In the other error handling fixture we compare 'scheduleWork' error
handling to 'requestAnimationFrame' and try to get as close as possible.
There is no 'timing out' feature with 'requestAnimationFrame' but
effectively the 'timing out' feature changes the order in which things
are called. So we just changed the order in the 'requestAnimationFrame'
version and that works well for illustrating the behavior we expect in
the 'scheduleWork' test.
**why make this change?:**
We need more test coverage of timed out callbacks.
**test plan:**
Executed the fixture manually in Firefox and Chrome. Results looked
good.
* fix rebase problems
* make fixture compensate for chrome JS speed
* ran prettier
* Remove 'cancelled' flag on callbackConfig in scheduler, add test
**what is the change?:**
- Instead of using a 'cancelled' flag on the callbackConfig, it's easier
to just check the state of the callbackConfig inside
'cancelScheduledWork' to determine if it's already been cancelled. That
way we don't have to remember to set the 'cancelled' flag every time we
call a callback or cancel it. One less thing to remember.
- We added a test for calling 'cancelScheduledWork' more than once,
which would have failed before.
Thanks @acdlite for suggesting this in code review. :)
**why make this change?:**
To increase stability of the schedule module, increase test coverage.
**test plan:**
Existing tests pass and we added a new test to cover this behavior.
* fix typo
* Fix for Flow issues in SimpleCacheProvider
**what is the change?:**
- Fixed some flow errors which were somehow swallowed when CI
originally
- Loosen flow types to avoid issue with recursive loop in Flow; https://github.com/facebook/flow/issues/5870
**why make this change?:**
To unbreak master and unblock other changes we want to make.
**test plan:**
Flow passes!
**issue:**
https://github.com/facebook/react/issues/12941
* Fix lints
* [simple-cache-provider] Use LRU cache eviction
Max size is hard-coded to 500. In the future, we should make this
configurable per resource.
* Evict PAGE_SIZE records from cache when max limit is reached
* Do not set selection when prior selection is undefined (#12062)
`restoreSelection` did not account for input elements that have changed
type after the commit phase. The new `text` input supported selection
but the old `email` did not and `setSelection` was incorrectly trying to
restore `null` selection state.
We also extend input type check in selection capabilities to cover cases
where input type is `search`, `tel`, `url`, or `password`.
* Add link to HTML spec for element types and selection
* Add reset button to ReplaceEmailInput
This commit adds a button to restore the original state of the
ReplaceEmailInput fixture so that it can be run multiple times without
refreshing the page.
**what is the change?:**
In a recent PR we were referencing some global variables and storing
local references to them.
To make things more natural, we co-opted the original name of the global
for our local reference. To make this work with Flow, we get the
original reference from 'window.requestAnimationFrame' and assign it to
'const requestAnimationFrame'.
Sometimes React is used in an environment where 'window' is not defined
- in that case we need to use something else, or hide the 'window'
reference somewhere.
We opted to use 'global' thinking that Babel transforms would fill that
in with the proper thing.
But for some of our fixtures we are not doing that transform on the
bundle.
**why make this change?:**
I want to unbreak this on master and then investigate more about what we
should do to fix this.
**test plan:**
run `yarn build` and open the fixtures.
**issue:**
https://github.com/facebook/react/issues/12930
* Use local references to global things inside 'scheduler'
**what is the change?:**
See title
**why make this change?:**
We want to avoid initially calling one version of an API and then later
accessing a polyfilled version.
**test plan:**
Run existing tests.
* Shim ReactScheduler for www
**what is the change?:**
In 'www' we want to reference the separate build of ReactScheduler,
which allows treating it as a separate module internally.
**why make this change?:**
We need to require the ReactScheduler before our rAF polyfill activates,
in order to customize which custom behaviors we want.
This is also a step towards being able to experiment with using it
outside of React.
**test plan:**
Ran tests, ran the build, and ran `test-build`.
* Generate a bundle for fb-www
**what is the change?:**
See title
**why make this change?:**
Splitting out the 'schedule' module allows us to load it before
polyfills kick in for rAF and other APIs.
And long term we want to split this into a separate module anyway, this
is a step towards that.
**test plan:**
I'll run the sync next week and verify that this all works. :)
* ran prettier
* fix rebase issues
* Change names of variables used for holding globals
This commit fixes an issue where assigning an empty string to required
text inputs triggers the invalid state in Firefox (~60.0.1).
It does this by first comparing the initial state value to the current
value property on the text element. This:
1. Prevents the validation issue
2. Avoids an extra DOM Mutation in some cases
CI builds should always use the `--frozen-lockfile` option. It will fail the build if the lockfile is out-of-date:
> If you need reproducible dependencies, which is usually the case with the continuous integration systems, you should pass --frozen-lockfile flag.
(https://yarnpkg.com/en/docs/cli/install/)
* [schedule] Use linked list instead of queue and map for storing cbs
NOTE: This PR depends on https://github.com/facebook/react/pull/12880
and https://github.com/facebook/react/pull/12884
Please review those first, and after they land Flarnie will rebase on
top of them.
---
**what is the change?:**
See title
**why make this change?:**
This seems to make the code simpler, and potentially saves space of
having an array and object around holding references to the callbacks.
**test plan:**
Run existing tests
* minor style improvements
* refactor conditionals in cancelScheduledWork for increased clarity
* Remove 'canUseDOM' condition and fix some flow issues w/callbackID type
**what is the change?:**
- Removed conditional which fell back to 'setTimeout' when the
environment doesn't have DOM. This appears to be an old polyfill used
for test environments and we don't use it any more.
- Fixed type definitions around the callbackID to be more accurate in
the scheduler itself, and more loose in the React code.
**why make this change?:**
To get Flow passing, simplify the scheduler code, make things accurate.
**test plan:**
Run tests and flow.
* Rewrite 'cancelScheduledWork' so that Flow accepts it
**what is the change?:**
Adding verification that 'previousCallbackConfig' and
'nextCallbackConfig' are not null before accessing properties on them.
Slightly concerned because this implementation relies on these
properties being untouched and correct on the config which is passed to
'cancelScheduledWork' but I guess we already rely heavily on that for
this whole approach. :\
**why make this change?:**
To get Flow passing.
Not sure why it passed earlier and in CI, but now it's not.
**test plan:**
`yarn flow dom` and other flow tests, lint, tests, etc.
* ran prettier
* Put back the fallback implementation of scheduler for node environment
**what is the change?:**
We had tried removing the fallback implementation of `scheduler` but
tests reminded us that this is important for supporting isomorphic uses
of React.
Long term we will move this out of the `schedule` module but for now
let's keep things simple.
**why make this change?:**
Keep things working!
**test plan:**
Ran tests and flow
* Shorten properties stored in objects by sheduler
**what is the change?:**
`previousScheduledCallback` -> `prev`
`nextScheduledCallback` -> `next`
**why make this change?:**
We want this package to be smaller, and less letters means less code
means smaller!
**test plan:**
ran existing tests
* further remove extra lines in scheduler
* Moved actual time fields from Profiler stateNode to Fiber
* Record actual time for all Fibers within a ProfileMode tree
* Changed how profiler accumulates time
This change gives up on accumulating time across renders of different priority, but in exchange- simplifies how the commit phase (reset) code works, and perhaps also makes the profiling code more compatible with future resuming behavior
* Adding 'schedule' fixture
**what is the change?:**
We need to test the `schedule` module against real live browser APIs. As
a quick solution we're writing a fixture for using in manual testing.
Later we plan on adding automated browser testing, using this or a
similar fixture as the test page.
**why make this change?:**
To further solidify test coverage for `schedule` before making further
improvements/refactors to the module.
**test plan:**
`open fixtures/schedule/index.html` and inspect the results. It should
be clear that things pass.
We also temporarily broke the scheduler and verified that this fixture
demonstrates the problems.
**issue:**
Internal task T29442940
* Made fixture tests display red or green border depending on pass/fail
**what is the change?:**
Added red/green solid/dashed border for test results when using the
schedule fixture.
We also tweaked the timing of the last test because it was on the line
in terms of whether it passed or failed.
**why make this change?:**
To make it faster to use the fixture - it takes more time to read
through the results line by line and check that they match what is
expected.
**test plan:**
Looked at the fixture, and also tried modifying a test to show what it
looks like when something fails.
**what is the change?:**
Renamed some methods, and made a method to advance a frame in the test
environment.
**why make this change?:**
We often need to simulate a frame passing with some amount of idle time
or lack of idle time, and the new method makes it easier to write that
out.
**test plan:**
Run the updated tests.
Also temporarily tried breaking the scheduler and verified that the
tests will fail.
**issue:**
See internal task T29442940
* add legacy context APIs warning in strict mode
* refactor if statement and the warning message
* add other flags for type check
* add component stack tree and refactor wording
* fix the nits
* Rewrite to a switch
I find it a bit easier to follow than many comparison conditions.
* Remove unnecessary assignments
They are being assigned below anyway. This is likely a copypasta from the FOCUS/BLUR special case (which *does* need those assignments).
* Unify "cancel" and "close" cases
Their logic is identical.
* Don't listen to media events at the top
* Add a unit test for double-invoking form events
* Remove an unused case and document it in a test
The case I added was wrong (just like including this event in the top level list was always wrong).
In fact it never bubbles, even for <img>. And since we don't special case it in the <img> event
attachment logic when we create it, we never supported <img onLoadStart> at all.
We could fix it. But Chrome doesn't support it either: https://bugs.chromium.org/p/chromium/issues/detail?id=458851.
Nobody asked us for it yet. And supporting it would require attaching an extra listener to every <img>.
So maybe we don't need it? Let's document the existing state of things.
* Add a test verifying we don't attach unnecessary listeners
* Add a comment
* Add a test for submit (bubbles: false)
**what is the change?:**
Test coverage checking that callbacks are called when they time out.
This test surfaced a bug and this commit includes the fix.
I want to refine this approach, but basically we can simulate time outs
by controlling the return value of 'now()' and the argument passed to
the rAF callback.
Next we will write a browser fixture to further test this against real
browser APIs.
**why make this change?:**
Better tests will keep this module working smoothly while we continue
refactoring and improving it.
**test plan:**
Run the new tests, see that it fails without the bug fix.
We were adding a listener at the root when we weren't meant to. Blames to e96dc14059.
This now alerts once (at FORM) instead of twice (at FORM, #document):
```
var Hello = class extends React.Component {
render() {
return (
<form onSubmit={(e) => {e.preventDefault(); alert('hi ' + e.nativeEvent.currentTarget.nodeName);}}>
<button>hi</button>
</form>
);
}
};
```
* Added start time parameter to Profiler onRender callback
* Profiler also captures commit time
* Only init Profiler stateNode if enableProfilerTimer feature flag enabled
* Extract base Jest config
This makes it easier to change the source config without affecting the build test config.
* Statically import the host config
This changes react-reconciler to import HostConfig instead of getting it through a function argument.
Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope).
This is still very broken.
* Add scaffolding for importing an inlined renderer
* Fix the build
* ES exports for renderer methods
* ES modules for host configs
* Remove closures from the reconciler
* Check each renderer's config with Flow
* Fix uncovered Flow issue
We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null.
Help Flow.
* Prettier
* Get rid of enable*Reconciler flags
They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence.
This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing.
Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead.
* Prettier again
* Fix Flow config creation issue
* Fix imprecise Flow typing
* Revert accidental changes
**what is the change?:**
Fix a typo which caused timed out callbacks to not be called.
**why make this change?:**
This is a bug caught by tests I'm in the process of writing, and we
should fix it asap.
**test plan:**
Tests in a WIP PR - will push and share the WIP test in comments on this
PR.
* Generate Flow config on install
We'll need to do pre-renderer Flow passes with different configs.
This is the first step to get it working. We only want the original version checked in.
* Create multiple Flow configs from a template
* Run Flow per renderer
* Lint
* Revert the environment consolidation
I thought this would be a bit cleaner at first because we now have non-environment files in this directory.
But Sebastian is changing these files at the same time so I want to avoid conflicts and keep the PR more tightly scoped. Undo.
* Misc
* Lint for untyped imports and enable Flow typing in ReactFiber
* Re-enable Flow for ReactFiber and fix Flow issues
* Avoid an invariant in DEV-only code
I just introduced it, but on a second thought, it's better to keep it as a warning.
* Address review
* Temporary fix for grabbing wrong rAF polyfill in ReactScheduler
**what is the change?:**
For now...
We need to grab a slightly different implementation of rAF internally at
FB than in Open Source. Making rAF a dependency of the ReactScheduler
module allows us to fork the dependency at FB.
NOTE: After this lands we have an alternative plan to make this module
separate from React and require it before our Facebook timer polyfills
are applied. But want to land this now to keep master in a working state
and fix bugs folks are seeing at Facebook.
Thanks @sebmarkbage @acdlite and @sophiebits for discussing the options
and trade-offs for solving this issue.
**why make this change?:**
This fixes a problem we're running into when experimenting with
ReactScheduler internally at Facebook, **and* it's part of our long term
plan to use dependency injection with the scheduler to make it easier to
test and adjust.
**test plan:**
Ran tests, lint, flow, and will manually test when syncing into
Facebook's codebase.
**issue:**
See internal task T29442940
* ran prettier
**what is the change?:**
We were setting a flag after some early returns, should have set it
right away.
To be fair, it's not clear how you can hit a problem with the current
state of things. Even if a callback is cancelled, it's still in the
'pendingCallbacks' queue until the rAF runs, and we only schedule a rAF
when there are pendingCallbacks in the queue.
But since this is obviously wrong, going to fix it.
We will be adding a regression test in a follow-up PR.
**why make this change?:**
To fix a random bug which was popping up.
**test plan:**
Adding a regression unit test in a follow-up PR.
**what is the change?:**
In some cases we had defined the 'callback' as taking two arguments,
when really we meant to indicate the second argument passed to
'scheduleWork'.
**why make this change?:**
For correctness and to unblock something @gaearon is working on. A bit
surprised Flow didn't catch this in the first place.
**test plan:**
Ran tests, flow, lint.
* Rename Scheduler methods more accurately
**what is the change?:**
```
rIC -> scheduleCallback
```
We will later expose a second method for different priority level, name
TBD. Since we only have one priority right now we can delay the
bikeshedding about the priority names.
cIC -> cancelScheduledCallback
This method can be used to cancel callbacks scheduled at any priority
level, and will remain named this way.
why make this change?:
Originally this module contained a polyfill for requestIdleCallback
and cancelIdleCallback but we are changing the behavior so it's no
longer just a polyfill. The new names are more semantic and distinguish
this from the original polyfill functionality.
**test plan:**
Ran the tests
**why make this change?:**
Getting this out of the way so things are more clear.
**Coming Up Next:**
- Switching from a Map of ids and an array to a linked list for storing
callbacks.
- Error handling
* callback -> work
* update callsites in new places after rebase
* fix typo
* Add TopLevelEventTypes
* Fix `ReactBrowserEventEmitter`
* Fix EventPluginUtils
* Fix TapEventPlugin
* Fix ResponderEventPlugin
* Update ReactDOMFiberComponent
* Fix BeforeInputEventPlugin
* Fix ChangeEventPlugin
* Fix EnterLeaveEventPlugin
* Add missing non top event type used in ChangeEventPlugin
* Fix SelectEventPlugin
* Fix SimpleEventPlugin
* Fix outstanding Flow issues and move TopLevelEventTypes
* Inline a list of all events in `ReactTestUtils`
* Fix tests
* Make it pretty
* Fix completly unrelated typo
* Don’t use map constructor because of IE11
* Update typings, revert changes to native code
* Make topLevelTypes in ResponderEventPlugin injectable and create DOM and ReactNative variant
* Set proper dependencies for DOMResponderEventPlugin
* Prettify
* Make some react dom tests no longer depend on internal API
* Use factories to create top level speific generic event modules
* Remove unused dependency
* Revert exposed module renaming, hide store creation, and inline dependency decleration
* Add Flow types to createResponderEventPlugin and its consumers
* Remove unused dependency
* Use opaque flow type for TopLevelType
* Add missing semis
* Use raw event names as top level identifer
* Upgrade baylon
This is required for parsing opaque flow types in our CI tests.
* Clean up flow types
* Revert Map changes of ReactBrowserEventEmitter
* Upgrade babel-* packages
Apparently local unit tests also have issues with parsing JavaScript
modules that contain opaque types (not sure why I didn't notice
earlier!?).
* Revert Map changes of SimpleEventPlugin
* Clean up ReactTestUtils
* Add missing semi
* Fix Flow issue
* Make TopLevelType clearer
* Favor for loops
* Explain the new DOMTopLevelEventTypes concept
* Use static injection for Responder plugin types
* Remove null check and rely on flow checks
* Add missing ResponderEventPlugin dependencies
* Use global state for `hasForceUpdate` instead of persisting to queue
Fixes a bug where `hasForceUpdate` was not reset on commit.
Ideally we'd use a tuple and return `hasForceUpdate` from
`processUpdateQueue`.
* Remove underscore and add comment
* Remove temporary variables
Fixes an oversight from #12600. getDerivedStateFromProps should fire
if either props *or* state have changed, but not if *neither* have
changed. This prevents a parent from re-rendering if a deep child
receives an update.
Previously, _owner would be null if you create an element inside forwardRef or inside a context consumer. This is used by ReactNativeFiberInspector when traversing the hierarchy and also to give more info in some warning texts. This also means you'll now correctly get a warning if you call setState inside one of these.
Test Plan: Tim tried it in the RN inspector.
* makes closure compiler threaded
* Dans PR with a closure compiler java version
* Remove unused dep
* Pin GCC
* Prettier
* Nit rename
* Fix error handling
* Name plugins consistently
* Fix lint
* Maybe this works?
* or this
* AppVeyor
* Fix lint
* Support concurrent primary and secondary renderers.
As a workaround to support multiple concurrent renderers, we categorize
some renderers as primary and others as secondary. We only expect
there to be two concurrent renderers at most: React Native (primary) and
Fabric (secondary); React DOM (primary) and React ART (secondary).
Secondary renderers store their context values on separate fields.
* Add back concurrent renderer warning
Only warn for two concurrent primary or two concurrent secondary renderers.
* Change "_secondary" suffix to "2"
#EveryBitCounts
* Timeout component
Adds Timeout component. If a promise is thrown from inside a Timeout component,
React will suspend the in-progress render from committing. When the promise
resolves, React will retry. If the render is suspended for longer than the
maximum threshold, the Timeout switches to a placeholder state.
The timeout threshold is defined as the minimum of:
- The expiration time of the current render
- The `ms` prop given to each Timeout component in the ancestor path of the
thrown promise.
* Add a test for nested fallbacks
Co-authored-by: Andrew Clark <acdlite@fb.com>
* Resume on promise rejection
React should resume rendering regardless of whether it resolves
or rejects.
* Wrap Suspense code in feature flag
* Children of a Timeout must be strict mode compatible
Async is not required for Suspense, but strict mode is.
* Simplify list of pending work
Some of this was added with "soft expiration" in mind, but now with our revised
model for how soft expiration will work, this isn't necessary.
It would be nice to remove more of this, but I think the list itself is inherent
because we need a way to track the start times, for <Timeout ms={ms} />.
* Only use the Timeout update queue to store promises, not for state
It already worked this way in practice.
* Wrap more Suspense-only paths in the feature flag
* Attach promise listener immediately on suspend
Instead of waiting for commit phase.
* Infer approximate start time using expiration time
* Remove list of pending priority levels
We can replicate almost all the functionality by tracking just five
separate levels: the highest/lowest priority pending levels, the
highest/lowest priority suspended levels, and the lowest pinged level.
We lose a bit of granularity, in that if there are multiple levels of
pending updates, only the first and last ones are known. But in practice
this likely isn't a big deal.
These heuristics are almost entirely isolated to a single module and
can be adjusted later, without API changes, if necessary.
Non-IO-bound work is not affected at all.
* ReactFiberPendingWork -> ReactFiberPendingPriority
* Renaming method names from "pending work" to "pending priority"
* Get rid of SuspenseThenable module
Idk why I thought this was neccessary
* Nits based on Sebastian's feedback
* More naming nits + comments
* Add test for hiding a suspended tree to unblock
* Revert change to expiration time rounding
This means you have to account for the start time approximation
heuristic when writing Suspense tests, but that's going to be
true regardless.
When updating the tests, I also made a fix related to offscreen
priority. We should never timeout inside a hidden tree.
* palceholder -> placeholder
Add a new component type, Profiler, that can be used to collect new render time metrics. Since this is a new, experimental API, it will be exported as React.unstable_Profiler initially.
Most of the functionality for this component has been added behind a feature flag, enableProfileModeMetrics. When the feature flag is disabled, the component will just render its children with no additional behavior. When the flag is enabled, React will also collect timing information and pass it to the onRender function (as described below).
* Support using id to cancel scheduled callback
**what is the change?:**
see title
**why make this change?:**
Once we support multiple callbacks you will need to use the id to
specify which callback you mean.
**test plan:**
Added a test, ran all tests, lint, etc.
* ran prettier
* fix lint
* Use object for storing callback info in scheduler
* Wrap initial test in a describe block
* Support multiple callbacks in `ReactScheduler`
**what is the change?:**
We keep a queue of callbacks instead of just one at a time, and call
them in order first by their timeoutTime and then by the order which
they were scheduled in.
**why make this change?:**
We plan on using this module to coordinate JS outside of React, so we
will need to schedule more than one callback at a time.
**test plan:**
Added a boatload of shiny new tests. :)
Plus ran all the old ones.
NOTE: The tests do not yet cover the vital logic of callbacks timing
out, and later commits will add the missing test coverage.
* Heuristic to avoid looking for timed out callbacks when none timed out
**what is the change?:**
Tracks the current soonest timeOut time for all scheduled callbacks.
**why make this change?:**
We were checking every scheduled callback to see if it timed out on
every tick. It's more efficient to skip that O(n) check if we know that
none have timed out.
**test plan:**
Ran existing tests.
Will write new tests to cover timeout behavior in more detail soon.
* Put multiple callback support under a disabled feature flag
**what is the change?:**
See title
**why make this change?:**
We don't have error handling in place yet, so should maintain the old
behavior until that is in place.
But want to get this far to continue making incremental changes.
**test plan:**
Updated and ran tests.
* Hide support for multiple callbacks under a feature flag
**what is the change?:**
see title
**why make this change?:**
We haven't added error handling yet, so should not expose this feature.
**test plan:**
Ran all tests, temporarily split out the tests for multiple callbacks
into separate file. Will recombine once we remove the flag.
* Fix nits from code review
See comments on https://github.com/facebook/react/pull/12743
* update checklist in comments
* Remove nested loop which calls additional timed out callbacks
**what is the change?:**
We used to re-run any callbacks which time out whilst other callbacks
are running, but now we will only check once for timed out callbacks
then then run them.
**why make this change?:**
To simplify the code and the behavior of this module.
**test plan:**
Ran all existing tests.
* Remove feature flag
**what is the change?:**
see title
**why make this change?:**
Because only React is using this, and it sounds like async. rendering
won't hit any different behavior due to these changes.
**test plan:**
Existing tests pass, and this allowed us to recombine all tests to run
in both 'test' and 'test-build' modes.
* remove outdated file
* fix typo
* Mark new component types with PerformedWork effect
* Don't do it for ForwardRef
Since this has some overhead and ForwardRef is likely going to be used around context, let's skip it.
We don't highlight ForwardRef alone in DevTools anyway.
```
$ jest
FAIL scripts/jest/dont-run-jest-directly.js
● Test suite failed to run
Don't run `jest` directly. Run `yarn test` instead.
> 1 | throw new Error("Don't run `jest` directly. Run `yarn test` instead.");
2 |
at Object.<anonymous> (scripts/jest/dont-run-jest-directly.js:1:96)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.866s
Ran all test suites.
```
* Add a failing test for forwardRef memoization
* Memoize forwardRef props and bail out on strict equality
* Bail out only when ref matches the current ref
**what is the change?:**
We had a condition to set either 'performance.now' or 'Date.now' as the
'now' function.
Then later we had another conditional checking again if
'performance.now' was supported, and using it if so, otherwise falling
back to 'Date.now'.
More efficient to just use the 'now' shortcut defined above.
**why make this change?:**
Fewer lines, clearer code.
**test plan:**
Now that we have tests we can run them :)
* Remove the 'alwaysUseRequestIdleCallbackPolyfill' feature flag
**what is the change?:**
Removes the feature flag 'alwaysUseRequestIdleCallbackPolyfill', such
that we **always** use the polyfill for requestIdleCallback.
**why make this change?:**
We have been testing this feature flag at 100% for some time internally,
and determined it works better for React than the native implementation.
Looks like RN was overriding the flag to use the native when possible,
but since no RN products are using 'async' mode it should be safe to
switch this flag over for RN as well.
**test plan:**
We have already been testing this internally for some time.
**issue:**
internal task t28128480
* fix mistaken conditional
* Add mocking of rAF, postMessage, and initial test for ReactScheduler
**what is the change?:**
- In all tests where we previously mocked rIC or relied on native
mocking which no longer works, we are now mocking rAF and postMessage.
- Also adds a basic initial test for ReactScheduler.
NOTE -> we do plan to write headless browser tests for ReactScheduler!
This is just an initial test, to verify that it works with the mocked
out browser APIs as expected.
**why make this change?:**
We need to mock out the browser APIs more completely for the new
'ReactScheduler' to work in our tests. Many tests are depending on it,
since it's used at a low level.
By mocking the browser APIs rather than the 'react-scheduler' module, we
enable testing the production bundles. This approach is trading
isolation for accuracy. These tests will be closer to a real use.
**test plan:**
run the tests :)
**issue:**
internal task T28128480
* Decouple update queue from Fiber type
The update queue is in need of a refactor. Recent bugfixes (#12528) have
exposed some flaws in how it's modeled. Upcoming features like Suspense
and [redacted] also rely on the update queue in ways that weren't
anticipated in the original design.
Major changes:
- Instead of boolean flags for `isReplace` and `isForceUpdate`, updates
have a `tag` field (like Fiber). This lowers the cost for adding new
types of updates.
- Render phase updates are special cased. Updates scheduled during
the render phase are dropped if the work-in-progress does not commit.
This is used for `getDerivedStateFrom{Props,Catch}`.
- `callbackList` has been replaced with a generic effect list. Aside
from callbacks, this is also used for `componentDidCatch`.
* Remove first class UpdateQueue types and use closures instead
I tried to avoid this at first, since we avoid it everywhere else in the Fiber
codebase, but since updates are not in a hot path, the trade off with file size
seems worth it.
* Store captured errors on a separate part of the update queue
This way they can be reused independently of updates like
getDerivedStateFromProps. This will be important for resuming.
* Revert back to storing hasForceUpdate on the update queue
Instead of using the effect tag. Ideally, this would be part of the
return type of processUpdateQueue.
* Rename UpdateQueue effect type back to Callback
I don't love this name either, but it's less confusing than UpdateQueue
I suppose. Conceptually, this is usually a callback: setState callbacks,
componentDidCatch. The only case that feels a bit weird is Timeouts,
which use this effect to attach a promise listener. I guess that kinda
fits, too.
* Call getDerivedStateFromProps every render, even if props did not change
Rather than enqueue a new setState updater for every props change, we
can skip the update queue entirely and merge the result into state at
the end. This makes more sense, since "receiving props" is not an event
that should be observed. It's still a bit weird, since eventually we do
persist the derived state (in other words, it accumulates).
* Store captured effects on separate list from "own" effects (callbacks)
For resuming, we need the ability to discard the "own" effects while
reusing the captured effects.
* Optimize for class components
Change `process` and `callback` to match the expected payload types
for class components. I had intended for the update queue to be reusable
for both class components and a future React API, but we'll likely have
to fork anyway.
* Only double-invoke render phase lifecycles functions in DEV
* Use global state to track currently processing queue in DEV
* checkPropTypes in updateContextProvider
* invalid “prop”
* `type not `types` .. :l
* test
* don’t need extra check with no spelling mistake (:
* change error message to specifically address provider
* don’t need class, add extra render to make sure good props go through
* nitpicky rename
* prettier
* switch to `Context.Provider`
* add stack to warning, add extra undefined check
* separate dev check
* add stack to test
* more efficient
* remove unused function
* prettier
* const to top
This is the first step - pulling the ReactDOMFrameScheduling module out
into a separate package.
Co-authored-by: Brandon Dail <aweary@users.noreply.github.com>
* Installed 3.x release of react-lifecycles-compat
* Updated ReactComponentLifeCycle-test and ReactDOMServerLifecycles-test to cover both polyfilled lifecycles in StrictMode
* Updated StrictMode warnings to not warn about polyfilled getSnapshotBeforeUpdate
* Added new "native-fb" and "native-fabric-fb" bundles.
* Split RN_DEV and RN_PROD bundle types into RN_OSS_DEV, RN_OSS_PROD, RN_FB_DEV, and RN_FB_PROD. (This is a bit redundant but it seemed the least intrusive way of supporting a forked feature flags file for these bundles.)
* Renamed FB_DEV and FB_PROD bundle types to be more explicitly for www (FB_WWW_DEV and FB_WWW_PROD)
* Removed Haste @providesModule headers from the RB-specific RN renderer bundles to avoid a duplicate name conflicts.
* Remove dynamic values from OSS RN feature flags. (Leave them in FB RN feature flags.)
* Updated the sync script(s) to account for new renderer type.
* Move ReactFeatureFlags.js shim to FB bundle only (since OSS bundle no longer needs dynamic values).
* Added new debug performance tests for AsyncMode, StrictMode, forwardRef, and context provider/consumer components.
* Updated performance labels to exclude AsyncMode and StrictMode.
* Added labels for forwardRef (and inner function) that mirror DevTools labels.
* Don't download bundle stats from master on CI
This was temporarily necessary in the past because we didn't have the logic that downloads actual *merge base* stats.
We do have that now as part of the Danger script. So we can remove this.
* Use absolute threshold for whether to show a change
* Download master stats, but only for other master builds
* Rewrite sizes
* Bump expiration for interactive updates to 150ms in production
**what is the change?:**
Changes the expiration deadline from 500ms to 150ms, only in production.
In development it will still be 500ms.
I'm thinking we may want to change the 'bucket size' too, will look into
that a bit.
**why make this change?:**
We need to ensure interactions are responsive enough in order to gather
more test data on async. mode.
**test plan:**
No tests failed - where shall we add a test for this?
* Add comments
* Move findNodeHandle into the renderers and use instantiation
This is just like ReactDOM does it. This also lets us get rid of injection
for findNodeHandle. Instead I move NativeMethodsMixin and ReactNativeComponent
to use instantiation.
* Refactor findHostInstance
The reconciler shouldn't expose the Fiber data structure. We should pass
the component instance to the reconciler, since the reconciler is the
thing that is supposed to be instancemap aware.
* Fix devtools injection
* Move view config registry to shims
This ensures that both Fabric and RN renderers share the same view config
registry since it is stateful.
I had to duplicate in the mocks for testing.
* Move createReactNativeComponentClass to shims and delete internal usage
Since createReactNativeComponentClass is just an alias for the register
there's no need to bundle it. This file should probably just move back
to RN too.
We already have one stateful module that contains all the view config.
We might as well store the event types there too. That way the shared
state is compartmentalized (and I can move it out in a follow up PR).
The view config registry also already has an appropriate place to call
processEventTypes so now we no longer have to do it in RN.
Will follow up with a PR to RN to remove that call.
These don't make much sense in Fabric, since Fabric will be async by default only.
And unmount+remove container is a sketchy API we should remove so we might
as well make sure modern containers enforce that.
This doesn't actually need to share any state because it goes through
the instance to the fiber structure. Since Fabric is on the same version
as RN, calling it on either renderer works.
There are no plans to enable async in the old renderer. In the new renderer
it only really makes sense to do from the main thread and probably from
native since it'll have to yield to native first.
This is not safe in general and therefore shouldn't be exposed to anything
other than React Native internals.
It will also need a different version in Fabric that will not have the
reactTag exposed.
* Don't render consumers that bailed out with bitmask even if there's a deeper matching child
* Use a render prop in the test
Without it, <Indirection> doesn't do anything because we bail out on constant element anyway.
That's not what we're testing, and could be confusing.
Based on a bug found in UFI2.
There have been several bugs related to the update queue (and
specifically baseState) recently, so I'm going to follow-up with some
refactoring to clean it up. This is a quick fix so we can ship a
patch release.
* Add regression tests for error boundary replay bugs
* Ensure the context stack is aligned if renderer throws
* Always throw when replaying a failed unit of work
Replaying a failed unit of work should always throw, because the render
phase is meant to be idempotent, If it doesn't throw, rethrow the
original error, so React's internal stack is not misaligned.
* Reset originalReplayError after replaying
* Typo fix
* Update user timing to record when we are about to commit
**what is the change?:**
After repeatedly logging '(React Tree Reconciliation)' we vary the
message slightly for the last reconciliation, which happens right before
we commit.
**why make this change?:**
When debugging performance in the devtools it will be helpful if we can
quickly see where the 'commit' happens in a potentially long list of
sliced '(React Tree Reconciliation)' logs.
**test plan:**
Built and ran one of the fixtures. Also ran the unit test.
(Flarnie will insert a screenshot)
* Ran prettier
* Fixes in response to code review
* Update snapshot tests
* Move isWorking assignment out of branches to top
* Stricter type for stopWorkLoopTimer args
* Fix DEV performance regression by avoiding Object.assign on Fibers
* Reduce allocations in hot path by reusing the stash
Since performUnitOfWork() is not reentrant, it should be safe to reuse the same stash every time instead of creating a new object.
* Add React.isValidElementType()
Per the conversation on #12453, there are a number of third-party
libraries (particularly those that generate higher-order components)
that are performing suboptimal validation of element types.
This commit exposes a function that can perform the desired check
without depending upon React internals.
* Move isValidElementType to shared/
* Update user timing to record the timeout deadline with 'waiting' events
**what is the change?:**
When we are processing work during reconciliation, we have a "timeout"
deadline to finish the work. It's a safety measure that forces things to
finish up synchronously if they are taking too long.
The "timeout" is different depending on the type of interaction which
triggered the reconciliation. We currently have a shorter "timeout" for
"interactive updates", meaning we will try to finish work faster if the
reconciliation was triggered by a click or other user interaction.
For collecting more data in our logs we want to differentiate the
'waiting for async callback...' events based on the "timeout" so I'm
adding that to the logging.
One interesting note - in one of the snapshot tests the "timeout" was
super high. Going to look into that.
**why make this change?:**
Right now we are debugging cases where an interaction triggers a
reconciliation and the "waiting for async callback...' events are too
long, getting blocked because the main thread is too busy. We are
keeping logs of these user timing events and want to filter to focus on
the reconciliation triggered by interaction.
**test plan:**
Manually tested and also updated snapshot tests.
(Flarnie will insert a screenshot)
* Improve wording of message
* ran prettier
* Test case for React Context bailing out unexpectedly
* This is 💯% definitely not the correct fix at all
* Revert "This is 💯% definitely not the correct fix at all"
This reverts commit 8686c0f6bdc1cba3056fb2212f3f7740c749d33a.
* Formatting + minor tweaks to the test
* Don't bail out on consumer child equality
* Tweak the comment
* Pretty lint
* Silly Dan
* Add a failing test for setState in cDM during batch.commit()
* Copy pasta
* Flush all follow-up Sync work on the committed batch
* Nit: Use performSyncWork
Call performSyncWork right after flushing the batch. Does effectively
the same thing by reusing the existing function.
Also added some comments.
* Delete accidentally duplicated test
These are based on the ReactNoop renderer, which we use to test React
itself. This gives library authors (Relay, Apollo, Redux, et al.) a way
to test their components for async compatibility.
- Pass `unstable_isAsync` to `TestRenderer.create` to create an async
renderer instance. This causes updates to be lazily flushed.
- `renderer.unstable_yield` tells React to yield execution after the
currently rendering component.
- `renderer.unstable_flushAll` flushes all pending async work, and
returns an array of yielded values.
- `renderer.unstable_flushThrough` receives an array of expected values,
begins rendering, and stops once those values have been yielded. It
returns the array of values that are actually yielded. The user should
assert that they are equal.
Although we've used this pattern successfully in our own tests, I'm not
sure if these are the final APIs we'll make public.
* Call getSnapshotBeforeUpdate in separate traversal, before mutation (aka revert db84b9a) and add unit test.
* Added a new timer to ReactDebugFiberPerf for Snapshot effects
* Implemented new getSnapshotBeforeUpdate lifecycle
* Store snapshot value from Fiber to instance (__reactInternalSnapshotBeforeUpdate)
* Use commitAllHostEffects() traversal for getSnapshotBeforeUpdate()
* Added DEV warnings and tests for new lifecycle
* Don't invoke legacy lifecycles if getSnapshotBeforeUpdate() is defined. DEV warn about this.
* Converted did-warn objects to Sets in ReactFiberClassComponent
* Replaced redundant new lifecycle checks in a few methods
* Check for polyfill suppress flag on cWU as well before warning
* Added Snapshot bit to HostEffectMask
Is this necessary? I'd like to use the package in enzyme to avoid having to recopy/paste the symbols for better debugging names, but at hard dep in enzyme proper on a version of react isn't gonna work. This seems safe since nothing explicitly depends on React in here?
* Add a failing test verifying componentInfo is missing
* Pass componentInfo to componentDidCatch and getDerivedStateFromCatch
* Only expect stack in DEV
* Don't pass the stack to getDerivedStateFromCatch()
FiberNode stateNode could be null
So I get TypeError:
```
at performWorkOnRoot (/tmp/my-project/node_modules/react-dom/cjs/react-dom.development.js:11014:24) TypeError: Cannot read property '_warnedAboutRefsInRender' of null
at findDOMNode (/tmp/my-project/node_modules/react-dom/cjs/react-dom.development.js:15264:55)
```
* Add a regression test for the context infinite loop
* Fix the bug
We set .return pointer inside the loop, but the top-level parent-child relationship happens outside.
This ensures the top-level parent's child points to the right copy of the parent.
Otherwise we may end up in a situation where (workInProgress === nextFiber) is never true and we loop forever.
* Support ForwardRef type of work in TestRenderer and ShallowRenderer.
* Release script now updates inter-package dependencies too (e.g. react-test-renderer depends on react-is).
We'll use this in www to test whether the polyfill is better at
scheduling high-pri async work than the native one. My preliminary tests
suggest "yes" but it's hard to say for certain, given how difficult it
is to consistently reproduce the starvation issues we've been seeing.
* Use module pattern so context stack is isolated per renderer
* Unify context implementations
Implements the new context API on top of the existing ReactStack that we
already use for host context and legacy context. Now there is a single
array that we push and pop from.
This makes the interrupt path slightly slower, since when we reset the
unit of work pointer, we have to iterate over the stack (like before)
*and* switch on the type of work (not like before). On the other hand,
this unifies all of the unwinding behavior in the UnwindWork module.
* Add DEV only warning if stack is not reset properly
We have other tests that would have caught this if resuming were enabled
in all cases, but since it's currently only enabled for error
boundaries, the test I've added to prevent a regression is a
bit contrived.
* Context providers and consumers should bail-out on already finished work
Fixes bug where a consumer would re-render even if its props and context
had not changed.
* Encode output as JSON string
* Add weights to random action generator
* Add context to triangle fuzz tester
* Move bailouts to as early as possible
* Bailout if neither context value nor children haven't changed (sCU)
* Change prop type invariant to a DEV-only warning
Using `new Map(iterable)` isn't supported in IE11, so it ends up trying to iterate through an empty map and these attributes don't get defined in properties. Since this is only run once on startup inlining the attributeName array is probably fine.
Changes `createResource` to return an object with `read` and `preload`
methods. Future methods may include `set`, `subscribe`, `invalidate`,
and so on.
* Don't expose ReactGlobalSharedState on React Native renderer
We should just go through the "react" package if need access to this one.
Removed the dependencies in React Native.
* No longer used by InspectorUtils
`oldProps` was null. This went uncaught by the unit tests because
ReactNoop did not use `oldProps` in either `prepareUpdate` or
`completeUpdate`. I added some invariants so we don't regress in
the future.
* Revert "Replace danger token with a refreshed facebook-open-source-bot token (#12295)"
This reverts commit 2d511479c4.
* Revert "Temporarily disable Danger in CI (#12291)"
This reverts commit 925fc93389.
* Add stack unwinding phase for handling errors
A rewrite of error handling, with semantics that more closely match
stack unwinding.
Errors that are thrown during the render phase unwind to the nearest
error boundary, like before. But rather than synchronously unmount the
children before retrying, we restart the failed subtree within the same
render phase. The failed children are still unmounted (as if all their
keys changed) but without an extra commit.
Commit phase errors are different. They work by scheduling an error on
the update queue of the error boundary. When we enter the render phase,
the error is popped off the queue. The rest of the algorithm is
the same.
This approach is designed to work for throwing non-errors, too, though
that feature is not implemented yet.
* Add experimental getDerivedStateFromCatch lifecycle
Fires during the render phase, so you can recover from an error within the same
pass. This aligns error boundaries more closely with try-catch semantics.
Let's keep this behind a feature flag until a future release. For now, the
recommendation is to keep using componentDidCatch. Eventually, the advice will
be to use getDerivedStateFromCatch for handling errors and componentDidCatch
only for logging.
* Reconcile twice to remount failed children, instead of using a boolean
* Handle effect immediately after its thrown
This way we don't have to store the thrown values on the effect list.
* ReactFiberIncompleteWork -> ReactFiberUnwindWork
* Remove startTime
* Remove TypeOfException
We don't need it yet. We'll reconsider once we add another exception type.
* Move replay to outer catch block
This moves it out of the hot path.
* Add test exercising public API to test BeforeInputEventPlugin + FallbackCompositionState
- I've adopted a similar approach to the existing test for BeforeInputEventPlugin
- I've simulated events and then assert the event handler for onBeforeInput is fired or not fired based on the test conditions
- The scenarios are tested against IE11, Webkite and Presto environment simulations
- I've encorporated what I understand to be the functionality in the FallbackCompositionState test
* Prettier
* Linting fixes
* Remove test for contenteditable in Presto - the contenteditable type is not supported in Presto powered browsers (Opera).
* Remove mention of Presto as this explicit condition is no longer handled in BeforeInputEventPlugin.
We still need to exercise usage of FallbackCompositionState though so let's keep a test where the env does not support Composition and Text events.
* Add tests for envs with only CompositionEvent support
* Remove internal tests no longer needed
* Shorten test case names to satisfy lint rules
* Add tests for onCompositionStart and onCompositionUpdte events
The BeforeInputEventPlugin is responsible for emitting these events so we need to add tests for this. This also ensure we exercise the code path that, L207, that was not previously exercised with the public tests.
If we have multiple RN renderers running simultaneously, we should be able to send a single event to all of them and only if it recognizes the event will it do anything with it. Crucially, this avoids the 'Unsupported top level event type "%s" dispatched' invariant in those cases.
* [experimental] simple-cache-provider
Pushing an early version of this for testing and demonstration purposes.
* Change invariant to DEV-only warning
* Use function overloading for createResource type
Expresses that primitive keys do not require a hash function, but
non-primitive keys do.
* More tests
* Use export *
* Make Record type a disjoint union
* Pass miss argument separate from key to avoid a closure
* Additional release script options for publishing canary versions
- `branch` specifies a branch other than master
- `local` skips pulling from the remote branch and checking CircleCI
- `tag` specifies an npm dist tag other than `latest` or `next`
We may add a higher-level `canary` option in the future.
* Address Brian's feedback:
- Updated description of `local` option
- Throws if the `latest` tag is specified for a prerelease version
* Disable DEV-only warnings for RN NativeMethodsMixin/create-react-class
* Tiny bit of cleanup
* Make strict-mode suppression check a little more robust
* [Danger] Use the PR's mergebase for a branch in the dangerfile instead of
the root commit's parent.
* [Danger] Get the full history to find the merge base
When a ref is removed from a class component, React now calls the previous ref-setter (if there was one) with null. Previously this was the case only for host component refs.
A new test has been added.
* add failed tests for <unstable_AsyncMode> with server rendering
* Fix server render with <unstable_AsyncMode> component
* Merge StrictMode and AsyncMode tests into Modes file
* Invoke both legacy and UNSAFE_ lifecycles when both are present
This is to support edge cases with eg create-react-class where a mixin defines a legacy lifecycle but the component being created defines an UNSAFE one (or vice versa).
I did not warn about this case because the warning would be a bit redundant with the deprecation warning which we will soon be enabling. I could be convinced to change my stance here though.
* Added explicit function-type check to SS ReactPartialRenderer
Accounts for the case where an event is dispatched synchronously from
inside another event, like `el.focus`. I've added a test, but in general
we need more coverage around this area.
* Switch to JSX API for context
80% sure this will be the final API. Merging this now so we can get this
into the next www sync in preparation for 16.3.
* Promote context to a stable API
* Updates inside controlled events (onChange) are sync even in async mode
This guarantees the DOM is in a consistent state before we yield back
to the browser.
We'll need to figure out a separate strategy for other
interactive events.
* Don't rely on flushing behavior of public batchedUpdates implementation
Flush work as an explicit step at the end of the event, right before
restoring controlled state.
* Interactive updates
At the beginning of an interactive browser event (events that fire as
the result of a user interaction, like a click), check for pending
updates that were scheduled in a previous interactive event. Flush the
pending updates synchronously so that the event handlers are up-to-date
before responding to the current event.
We now have three classes of events:
- Controlled events. Updates are always flushed synchronously.
- Interactive events. Updates are async, unless another a subsequent
event is fired before it can complete, as described above. They are
also slightly higher priority than a normal async update.
- Non-interactive events. These are treated as normal, low-priority
async updates.
* Flush lowest pending interactive update time
Accounts for case when multiple interactive updates are scheduled at
different priorities. This can happen when an interactive event is
dispatched inside an async subtree, and there's an event handler on
an ancestor that is outside the subtree.
* Update comment about restoring controlled components
* ReactDOM.flushControlled
New API for wrapping event handlers that need to fire before React
yields to the browser. Previously we thought that flushSync was
sufficient for this use case, but it turns out that flushSync is only
safe if you're guaranteed to be at the top of the stack; that is, if
you know for sure that your event handler is not nested inside another
React event handler or lifecycle. This isn't true for cases like
el.focus, el.click, or dispatchEvent, where an event handler can be
invoked synchronously from inside an existing stack.
flushControlled has similar semantics to batchedUpdates, where if you
nest multiple batches, the work is not flushed until the end of the
outermost batch. The work is not guaranteed to synchronously flush, as
with flushSync, but it is guaranteed to flush before React yields to
the browser.
flushSync is still the preferred API in most cases, such as inside
a requestAnimationFrame callback.
* Test that flushControlled does not flush inside batchedUpdates
* Make flushControlled a void function
In the future, we may want to return a thenable work object. For now,
we'll return nothing.
* flushControlled -> unstable_flushControlled
* Replace unstable_AsyncComponent with Unstable_AsyncMode
Mirrors the StrictMode API and uses the new Mode type of work.
* internalContextTag -> mode
Change this now that we have a better name
* Unstable_ -> unstable_
* Suppress unsafe/deprecation warnings for polyfilled components.
* Don't invoke deprecated lifecycles if static gDSFP exists.
* Applied recent changes to server rendering also
A new feature flag has been added, debugRenderPhaseSideEffectsForStrictMode. When enabled, StrictMode subtrees will also double-invoke lifecycles in the same way as debugRenderPhaseSideEffects.
By default, this flag is enabled for __DEV__ only. Internally we can toggle it with a GK.
This breaks several of our incremental tests which make use of the noop-renderer. Updating the tests to account for the double-rendering in development mode makes them significantly more complicated. The most straight forward fix for this will be to convert them to be run as internal tests only. I believe this is reasonable since we are the only people making use of the noop renderer.
Builds on top of PR #12083 and resolves issue #12044.
Coalesces deprecation warnings until the commit phase. This proposal extends the utility introduced in #12060 to also coalesce deprecation warnings.
New warning format will look like this:
> componentWillMount is deprecated and will be removed in the next major version. Use componentDidMount instead. As a temporary workaround, you can rename to UNSAFE_componentWillMount.
>
> Please update the following components: Foo, Bar
>
> Learn more about this warning here:
> https://fb.me/react-async-component-lifecycle-hooks
* New context API
Introduces a declarative context API that propagates updates even when
shouldComponentUpdate returns false.
* Fuzz tester for context
* Use ReactElement for provider and consumer children
* Unify more branches in createFiberFromElement
* Compare context values using Object.is
Same semantics as PureComponent/shallowEqual.
* Add support for Provider and Consumer to server-side renderer
* Store providers on global stack
Rather than using a linked list stored on the context type. The global
stack can be reset in case of an interruption or error, whereas with the
linked list implementation, you'd need to keep track of every
context type.
* Put new context API behind a feature flag
We'll enable this in www only for now.
* Store nearest provider on context object
* Handle reentrancy in server renderer
Context stack should be per server renderer instance.
* Bailout of consumer updates using bitmask
The context type defines an optional function that compares two context
values, returning a bitfield. A consumer may specify the bits it needs
for rendering. If a provider's context changes, and the consumer's bits
do not intersect with the changed bits, we can skip the consumer.
This is similar to how selectors are used in Redux but fast enough to do
while scanning the tree. The only user code involved is the function
that computes the changed bits. But that's only called once per provider
update, not for every consumer.
* Store current value and changed bits on context object
There are fewer providers than consumers, so better to do this work
at the provider.
* Use maximum of 31 bits for bitmask
This is the largest integer size in V8 on 32-bit systems. Warn in
development if too large a number is used.
* ProviderComponent -> ContextProvider, ConsumerComponent -> ContextConsumer
* Inline Object.is
* Warn if multiple renderers concurrently render the same context provider
Let's see if we can get away with not supporting this for now. If it
turns out that it's needed, we can fall back to backtracking the
fiber return path.
* Nits that came up during review
Added new StrictMode component for enabling async warnings (without enabling async rendering). This component can be used in the future to help with other warnings (eg compilation, Fabric).
Update debugRenderPhaseSideEffects behavior
This feature flag no longer double-invokes componentWillMount, componentWillReceiveProps, componentWillUpdate, or shouldComponentUpdate.
It continues to double-invoke the constructor, render, and setState updater functions as well as the recently added, static getDerivedStateFromProps method
Tests have been updated.
While writing tests for unsafe async warnings, I noticed that in certain cases, errors were swallowed by the toWarnDev matcher and resulted in confusing test failures. For example, if an error prevented the code being tested from logging an expected warning- the test would fail saying that the warning hadn't been logged rather than reporting the unexpected error. I think a better approach for this is to always treat caught errors as the highest-priority reason for failing a test.
I reran all of the test cases for this matcher that I originally ran with PR #11786 and ensured they all still pass.
* Added unsafe_* lifecycles and deprecation warnings
If the old lifecycle hooks (componentWillMount, componentWillUpdate, componentWillReceiveProps) are detected, these methods will be called and a deprecation warning will be logged. (In other words, we do not check for both the presence of the old and new lifecycles.) This commit is expected to fail tests.
* Ran lifecycle hook codemod over project
This should handle the bulk of the updates. I will manually update TypeScript and CoffeeScript tests with another commit.
The actual command run with this commit was: jscodeshift --parser=flow -t ../react-codemod/transforms/rename-unsafe-lifecycles.js ./packages/**/src/**/*.js
* Manually migrated CoffeeScript and TypeScript tests
* Added inline note to createReactClassIntegration-test
Explaining why lifecycles hooks have not been renamed in this test.
* Udated NativeMethodsMixin with new lifecycle hooks
* Added static getDerivedStateFromProps to ReactPartialRenderer
Also added a new set of tests focused on server side lifecycle hooks.
* Added getDerivedStateFromProps to shallow renderer
Also added warnings for several cases involving getDerivedStateFromProps() as well as the deprecated lifecycles.
Also added tests for the above.
* Dedupe and DEV-only deprecation warning in server renderer
* Renamed unsafe_* prefix to UNSAFE_* to be more noticeable
* Added getDerivedStateFromProps to ReactFiberClassComponent
Also updated class component and lifecyle tests to cover the added functionality.
* Warn about UNSAFE_componentWillRecieveProps misspelling
* Added tests to createReactClassIntegration for new lifecycles
* Added warning for stateless functional components with gDSFP
* Added createReactClass test for static gDSFP
* Moved lifecycle deprecation warnings behind (disabled) feature flag
Updated tests accordingly, by temporarily splitting tests that were specific to this feature-flag into their own, internal tests. This was the only way I knew of to interact with the feature flag without breaking our build/dist tests.
* Tidying up
* Tweaked warning message wording slightly
Replaced 'You may may have returned undefined.' with 'You may have returned undefined.'
* Replaced truthy partialState checks with != null
* Call getDerivedStateFromProps via .call(null) to prevent type access
* Move shallow-renderer didWarn* maps off the instance
* Only call getDerivedStateFromProps if props instance has changed
* Avoid creating new state object if not necessary
* Inject state as a param to callGetDerivedStateFromProps
This value will be either workInProgress.memoizedState (for updates) or instance.state (for initialization).
* Explicitly warn about uninitialized state before calling getDerivedStateFromProps.
And added some new tests for this change.
Also:
* Improved a couple of falsy null/undefined checks to more explicitly check for null or undefined.
* Made some small tweaks to ReactFiberClassComponent WRT when and how it reads instance.state and sets to null.
* Improved wording for deprecation lifecycle warnings
* Fix state-regression for module-pattern components
Also add support for new static getDerivedStateFromProps method
* Adds danger_js with an initial rule for warning about large PRs
Signed-off-by: Anandaroop Roy <roop@artsymail.com>
* [WIP] Get the before and after for the build results
* [Dev] More work on the Dangerfile
* [Danger] Split the reports into sections based on their package
* Remove the --extract-errors on the circle build
* [Danger] Improve the lookup for previous -> current build to also include the environment
* Fix rebase
The TestUtils lost media events when they were pulled out of the
topLevelTypes constant. This commit adds them back by concatenating
the media event keys to the list of top level types.
We want to start refactoring some of the event constants, but we don't
have a great way to confirm media events work as intended. This commit
adds a new DOM test fixture to verify that media events bubble.
In absence of a value, radio and checkboxes report a value of
"on". Between 16 and 16.2, we assigned a node's value to it's current
value in order to "dettach" it from defaultValue. This had the
unfortunate side-effect of assigning value="on" to radio and
checkboxes
Related issues:
https://github.com/facebook/react/issues/11998
* Added 'flow-coverage-report' package for discussion
* Aded flow-coverage command and configuration file
* Moved FLow coverage config file to scripts/flow/coverage-config
* Moved Flow coverage config back to root as dotfile
* Runs a lint rule on tests only that errors if it sees `fdescribe` or `fit` calls.
* Changes `file:` to `link:` for our custom, internal rules (just to simplify updating these in the future).
* Updates `eslint` from 3.10 -> 4.1 and `babel-eslint` from 7.1 -> 8.0 so that we can run this new rule only against tests.
* Add warning in server renderer if class doesn't extend React.Component
In dev mode, while server rendering, a warning will be thrown if there is a class that doesn't extend React.Component.
* Use `.toWarnDev` matcher and deduplicate warnings
* Deduplicate client-side warning if class doesn't extend React.Component
* Default componentName to Unknown if null
Removes the `useSyncScheduling` option from the HostConfig, since it's
no longer needed. Instead of globally flipping between sync and async,
our strategy will be to opt-in specific trees and subtrees.
* Updated misleading error message in production environment when adding ref to a functional component
* Reverted changes to codes.json
* Updated error message
* Warn about spying on the console
* Added suppress warning flag for spyOn(console)
* Nits
* Removed spy-on-console guard
* Fixed a potential source of false-positives in toWarnDev() matcher
Also updated (most of) ReactIncrementalErrorLogging-test.internal to use the new matcher
* Removed unused third param to spyOn
* Improved clarity of inline comments
* Removed unused normalizeCodeLocInfo() method
* enables ctrl + enter for keypress event on browsers other than firefox
* makes comment more descriptive as to affected platforms
* reverting fiber results
* Reset changes to results.json
* Remove old test file
* Add tests in the right place
* Move build/packages/* to build/node_modules/*
This fixes Node resolution in that folder and lets us require() packages in it in Node shell for manual testing.
* Link fixtures to packages/node_modules
This updates the location and also uses link: instead of file: to avoid Yarn caching the folder contents.
* Bump deps to Jest 22
* Prevent jsdom from logging intentionally thrown errors
This relies on our existing special field that we use to mute errors.
Perhaps, it would be better to instead rely on preventDefault() directly.
I outlined a possible strategy here: https://github.com/facebook/react/issues/11098#issuecomment-355032539
* Update snapshots
* Mock out a method called by ReactART that now throws
* Calling .click() no longer works, dispatch event instead
* Fix incorrect SVG element creation in test
* Render SVG elements inside <svg> to avoid extra warnings
* Fix range input test to use numeric value
* Fix creating SVG element in test
* Replace brittle test that relied on jsdom behavior
The test passed in jsdom due to its implementation details.
The original intention was to test the mutation method, but it was removed a while ago.
Following @nhunzaker's suggestion, I moved the tests to ReactDOMInput and adjusted them to not rely on implementation details.
* Add a workaround for the expected extra client-side warning
This is a bit ugly but it's just two places. I think we can live with this.
* Only warn once for mismatches caused by bad attribute casing
We used to warn both about bad casing and about a mismatch.
The mismatch warning was a bit confusing. We didn't know we warned twice because jsdom didn't faithfully emulate SVG.
This changes the behavior to only leave the warning about bad casing if that's what caused the mismatch.
It also adjusts the test to have an expectation that matches the real world behavior.
* Add an expected warning per comment in the same test
* Migrated several additional tests to use new .toWarnDev() matcher
* Migrated ReactDOMComponent-test to use .toWarnDev() matcher
Note this test previous had some hacky logic to verify errors were reported against unique line numbers. Since the new matcher doesn't suppor this, I replaced this check with an equivalent (I think) comparison of unique DOM elements (eg div -> span)
* Updated several additional tests to use the new .toWarnDev() matcher
* Updated many more tests to use .toWarnDev()
* Updated several additional tests to use .toWarnDev() matcher
* Updated ReactElementValidator to distinguish between Array and Object in its warning. Also updated its test to use .toWarnDev() matcher.
* Updated a couple of additional tests
* Removed unused normalizeCodeLocInfo() methods
* Migrated several additional tests to use new .toWarnDev() matcher
* Migrated ReactDOMComponent-test to use .toWarnDev() matcher
Note this test previous had some hacky logic to verify errors were reported against unique line numbers. Since the new matcher doesn't suppor this, I replaced this check with an equivalent (I think) comparison of unique DOM elements (eg div -> span)
* Updated several additional tests to use the new .toWarnDev() matcher
* Updated many more tests to use .toWarnDev()
* Added toWarnInDev matcher and connected to 1 test
* Added .toLowPriorityWarnDev() matcher
* Reply Jest spy with custom spy. Unregister spy after toWarnDev() so unexpected console.error/warn calls will fail tests.
* console warn/error throws immediately in tests by default (if not spied on)
* Pass-thru console message before erroring to make it easier to identify
* More robustly handle unexpected warnings within try/catch
* Error message includes remaining expected warnings in addition to unexpected warning
I'm running out of ideas to keep these commit messages entertaining. Thankfully this should keep the CI green and we can forget any of it ever happened.
We added this to Flow in v0.25 (about 2 years ago), but never actually
deprecated the legacy `declare var exports` syntax. Hoping to do that
soon, so clearing up uses that I can find.
Test Plan: flow
The BeforeInputPlugin dispatches null elements in an array if
composition or beforeInput events are not extracted. This causes a
an extra array allocation, but more importantly creates null states in
later event dispatch methods that are annoying to account for.
This commit makes it so that BeforeInputPlugin never returns a null
element inside an array.
* Add basic snapshot tests to ReactART components (Circle, Rectangle, Wedge)
* More tests on Circle, Rectangle, Wedge
* linc warning fixes
* - remove tests to Wedge component internal function
* More test on Wedge component, update snapshots
* Call and Return components should use ReactElement
ReactChildFiber contains lots of branches that do the same thing for
different child types. We can unify them by having more child types be
ReactElements. This requires that the `type` and `key` fields are
sufficient to determine the identity of the child.
The main benefit is decreased file size, especially as we add more
component types, like context providers and consumers.
This updates Call and Return components to use ReactElement. Portals are
left alone for now because their identity includes the host instance.
* Move server render invariant for call and return types
* Sort ReactElement type checks by most likely
* Performance timeline should skip over call components
Don't think these were intentionally omitted from the blacklist of
component types.
I went ahead and updated getComponentName to include special types, even
though I don't think they're used anywhere right now.
* Remove surrounding brackets from internal display names
* use different eslint config for es6 and es5
* remove confusing eslint/baseConfig.js & add more eslint setting for es5, es6
* more clear way to run eslint on es5 & es6 file
* seperate ESNext, ES6, ES6 path, and use different lint config
* rename eslint config file & update eslint rules
* Undo yarn.lock changes
* Rename a file
* Remove unnecessary exceptions
* Refactor a little bit
* Refactor and tweak the logic
* Minor issues
* fix#11759. false positive warning in IE11 when using React.Fragment
* simplify createElementWithValidation type check
* fix mistake
* Add an explanation
* We shouldn't use `number` for anything else
* Clarify further
* Harden tests around init/addition/update/removal of aliased attributes
I noticed some patterns weren't being tested.
* Call setValueForProperty() for null and undefined
The branching before the call is unnecessary because setValueForProperty() already
has an internal branch that delegates to deleteValueForProperty() for null and
undefined through the shouldIgnoreValue() check.
The goal is to start unifying these methods because their separation doesn't
reflect the current behavior (e.g. for unknown properties) anymore, and obscures
what actually happens with different inputs.
* Inline deleteValueForProperty() into setValueForProperty()
Now we don't read propertyInfo twice in this case.
I also dropped a few early returns. I added them a while ago when we had
Stack-only tracking of DOM operations, and some operations were being
counted twice because of how this code is structured. This isn't a problem
anymore (both because we don't track operations, and because I've just
inlined this method call).
* Inline deleteValueForAttribute() into setValueForAttribute()
The special cases for null and undefined already exist in setValueForAttribute().
* Delete some dead code
* Make setValueForAttribute() a branch of setValueForProperty()
Their naming is pretty confusing by now. For example setValueForProperty()
calls setValueForAttribute() when shouldSetAttribute() is false (!). I want
to refactor (as in, inline and then maybe factor it out differently) the relation
between them. For now, I'm consolidating the callers to use setValueForProperty().
* Make it more obvious where we skip and when we reset attributes
The naming of these methods is still very vague and conflicting in some cases.
Will need further work.
* Rewrite setValueForProperty() with early exits
This makes the flow clearer in my opinion.
* Move shouldIgnoreValue() into DOMProperty
It was previously duplicated.
It's also suspiciously similar in purpose to shouldTreatAttributeValueAsNull()
so I want to see if there is a way to unify them.
* Use more specific methods for testing validity
* Unify shouldTreatAttributeValueAsNull() and shouldIgnoreValue()
* Remove shouldSetAttribute()
Its naming was confusing and it was used all over the place instead of more specific checks.
Now that we only have one call site, we might as well inline and get rid of it.
* Remove unnecessary condition
* Remove another unnecessary condition
* Add Flow coverage
* Oops
* Fix lint (ESLint complains about Flow suppression)
* Fix treatment of Symbol/Function values on boolean attributes
They weren't being properly skipped because of the early return.
I added tests for this case.
* Avoid getPropertyInfo() calls
I think this PR looks worse on benchmarks because we have to read propertyInfo in different places.
Originally I tried to get rid of propertyInfo, but looks like it's important for performance after all.
So now I'm going into the opposite direction, and precompute propertyInfo as early as possible, and then just pass it around.
This way we can avoid extra lookups but keep functions nice and modular.
* Pass propertyInfo as argument to getValueForProperty()
It always exists because this function is only called for known properties.
* Make it clearer this branch is boolean-specific
I wrote this and then got confused myself.
* Memoize whether propertyInfo accepts boolean value
Since we run these checks for all booleans, might as well remember it.
* Fix a crash when numeric property is given a Symbol
* Record attribute table
The changes reflect that SSR doesn't crash with symbols anymore (and just warns, consistently with the client).
* Refactor attribute initialization
Instead of using flags, explicitly group similar attributes/properties.
* Optimization: we know built-in attributes are never invalid
* Use strict comparison
* Rename methods for clarity
* Lint nit
* Minor tweaks
* Document all the different attribute types
* Deduplication of warn selected on option
- Wrote a failing test
- Deduplication when selected is set on option
* Ran yarn preitter
* Fixed PR request
- Moved dedupe test to above
- Moved && case to seperate if to seperate static and dynamic things
- Render'd component twice
* Actually check for deduplication
* Minor nits
* Harden tests around init/addition/update/removal of aliased attributes
I noticed some patterns weren't being tested.
* Call setValueForProperty() for null and undefined
The branching before the call is unnecessary because setValueForProperty() already
has an internal branch that delegates to deleteValueForProperty() for null and
undefined through the shouldIgnoreValue() check.
The goal is to start unifying these methods because their separation doesn't
reflect the current behavior (e.g. for unknown properties) anymore, and obscures
what actually happens with different inputs.
* Inline deleteValueForProperty() into setValueForProperty()
Now we don't read propertyInfo twice in this case.
I also dropped a few early returns. I added them a while ago when we had
Stack-only tracking of DOM operations, and some operations were being
counted twice because of how this code is structured. This isn't a problem
anymore (both because we don't track operations, and because I've just
inlined this method call).
* Inline deleteValueForAttribute() into setValueForAttribute()
The special cases for null and undefined already exist in setValueForAttribute().
* Delete some dead code
* Make setValueForAttribute() a branch of setValueForProperty()
Their naming is pretty confusing by now. For example setValueForProperty()
calls setValueForAttribute() when shouldSetAttribute() is false (!). I want
to refactor (as in, inline and then maybe factor it out differently) the relation
between them. For now, I'm consolidating the callers to use setValueForProperty().
* Make it more obvious where we skip and when we reset attributes
The naming of these methods is still very vague and conflicting in some cases.
Will need further work.
* Rewrite setValueForProperty() with early exits
This makes the flow clearer in my opinion.
* Move shouldIgnoreValue() into DOMProperty
It was previously duplicated.
It's also suspiciously similar in purpose to shouldTreatAttributeValueAsNull()
so I want to see if there is a way to unify them.
* Use more specific methods for testing validity
* Unify shouldTreatAttributeValueAsNull() and shouldIgnoreValue()
* Remove shouldSetAttribute()
Its naming was confusing and it was used all over the place instead of more specific checks.
Now that we only have one call site, we might as well inline and get rid of it.
* Remove unnecessary condition
* Remove another unnecessary condition
* Add Flow coverage
* Oops
* Fix lint (ESLint complains about Flow suppression)
* Remove EventListener fbjs utility
EventListener normalizes event subscription for <= IE8. This is no
longer necessary. element.addEventListener is sufficient.
* Remove an extra allocation for open source bundles
* Split into two functions to avoid extra runtime checks
* Revert unrelated changes
* Add a test-only transform to catch infinite loops
* Only track iteration count, not time
This makes the detection dramatically faster, and is okay in our case because we don't have tests that iterate so much.
* Use clearer naming
* Set different limits for tests
* Fail tests with infinite loops even if the error was caught
* Add a test
* ValidateDOMNesting tests(#11299)
* Rewrite tests using only public API.
* Modified the tests to prevent duplication of code.
* Code review changes implemented.
* Removed the .internal from the test file name as
its now written using public APIs.
* Remove mutation
* Remove unnecessary argument
Now that we pass warnings, we don't need to pass a boolean.
* Move things around a bit, and add component stack assertions
* Rewrite the build scripts
* Don't crash when doing FB-only builds
* Group sync imports under Sync.*
* Don't print known errors twice
* Use an exclamation that aligns vertically
* Fix autoFocus for hydration content when it is mismatched
* Add a test for mismatched content
* Fix a test for production
* Fix a spec description and verify console.error output
* Run prettier
* finalizeInitialChildren always returns `true`
* Revert "finalizeInitialChildren always returns `true`"
This reverts commit 58edd228046bcafcbcd04a70cb5e78520b50a07e.
* Add a TODO comment
* Update ReactServerRendering-test.js
* Update ReactServerRendering-test.js
* Rewrite the comment
* Change build process to include npm pack and unpacking generated packages to corresponding build directories.
* Update function name, change to use os's default temp directory
* appending uuid to temp npm packaging directory.
* Ensure value and defaultValue do not assign functions and symbols
* Eliminate assignProperty method from ReactDOMInput
* Restore original placement of defaultValue reservedProp
* Reduce branching. Make assignment more consistent
* Control for warnings in symbol/function tests
* Add boolean to readOnly assignments
* Tweak the tests
* Invalid value attributes should convert to an empty string
* Revert ChangeEventPlugin update. See #11746
* Format
* Replace shouldSetAttribute call with value specific type check
DOMProperty.shouldSetAttribute runs a few other checks that aren't
appropriate for determining if a value or defaultValue should be
assigned on an input. This commit replaces that call with an input
specific check.
* Remove unused import
* Eliminate unnecessary numeric equality checks (#11751)
* Eliminate unnecessary numeric equality checks
This commit changes the way numeric equality for number inputs works
such that it compares against `input.valueAsNumber`. This eliminates
quite a bit of branching around numeric equality.
* There is no need to compare valueAsNumber
* Add test cases for empty string to 0.
* Avoid implicit boolean JSX props
* Split up numeric equality test to isolate eslint disable command
* Fix typo in ReactDOMInput test
* Add todos
* Update the attribute table
I updated ReactDOMInput.synchronizeDefaultValue such that it assignes
the defaultValue property instead of the value attribute. I never
followed up on the ChangeEventPlugin's on blur behavior.
* Inline HTML and SVG configs into DOMProperty
* Replace invariants with warnings
These invariants can only happen if *we* mess up, and happen during init time.
So it's safe to make these warnings, as they would fail the tests anyway.
* Clearer variable naming
* Use defaultValue instead of setAttribute('value')
This commit replaces the method of synchronizing an input's value
attribute from using setAttribute to assigning defaultValue. This has
several benefits:
- Fixes issue where IE10+ and Edge password icon disappears (#7328)
- Fixes issue where toggling input types hides display value on dates
in Safari (unreported)
- Removes mutationMethod behaviors from DOMPropertyOperations
* initialValue in Input wrapperState is always a string
* The value property is assigned before the value attribute. Fix related tests.
* Remove initial value tests in ReactDOMInput
I added these tests after removing the `value` mutation
method. However they do not add any additional value over existing
tests.
* Improve clarity of value checks in ReactDOMInput.postMountWrapper
* Remove value and defaultValue from InputWithWrapperState type
They are already included in the type definition for HTMLInputElement
* Inline stringification of value in ReactDOMInput
Avoids eagier stringification and makes usage more consistent.
* Use consistent value/defaultValue presence in postMountHook
Other methods in ReactDOMInput check for null instead of
hasOwnProperty.
* Add missing semicolon
* Remove unused value argument in ReactDOMInput test
* Address cases where a value switches to undefined
When a controlled input value switches to undefined, it reverts back
to the initial state of the controlled input.
We didn't have test coverage for this case, so I've added two describe
blocks to cover both null and undefined.
* Test: create TapEventPlugin-test
* move TapEventPlugin to TapEventPlugin-test.internal.js from ReactBrowserEventEmitter-test.internal.js
* Prittier: run prittier
* run prittier
* Fix: fix CI test error
fix CI test error by lint
* Test: remove TapEventPlugin test code
* remove TapEventPlugin test code from ReactBrowserEventEmitter-test.internal.js
* Use `this` inside invokeGuardedCallback
It's slightly odd but that's exactly how our www fork works.
Might as well do it in the open source version to make it clear we rely on context here.
* Move invokeGuardedCallback into a separate file
This lets us introduce forks for it.
* Add a www fork for invokeGuardedCallback
* Fix Flow
* WIP:use public API
* ReactPortal shifted to shared:all passed
* wrote createPortal method for ReactNoop.(#11299)
* imported ReactNodeList type into ReactNoop.(#11299)
* createPortal method implemented.(#11299)
* exec yarn prettier-all.(#11299)
* Unify the way we fork modules
* Replace rollup-plugin-alias with our own plugin
This does exactly what we need and doesn't suffer from https://github.com/rollup/rollup-plugin-alias/issues/34.
* Move the new plugin to its own file
* Rename variable for consistency
I settled on calling them "forks" since we already have a different concept of "shims".
* Move fork config into its own file
* Rewrite SelectEventPlugin-test to test behavior using Public API
* Minor refactor
* Make sure that we test that "focus" event is ignored
Use newer API when creating events
* Rewrote the other test to use Public API as well
* Tweak the test
* Remove -internal suffix
* Oops
* Warn if `document` is missing by the time invokeGuardedCallback runs in DEV
* Typo
* Add a comment
* Use invariant() instead
* Create event immediately for clarity
* rewrite two phase traversal tests with public APIs
* rewrite enter/leave tests
* lift render into beforeEach, organise variables
* move getLowestCommonAncestor test
* remove internal tree traversal test
* fix linter errors
* move creation of outer nodes into {before,after}Each
* explain why getLowestCommonAncestor test was moved
* remove unnessecary ARG and ARG2 token
these were used for testing the internal API to simulate synthetic
events passed to traverseEnterLeave. since we're now dealing with
actual synthetic events we can remove them.
* run prettier
In the current implementation, pendingProps is null if there are no new
props since the last commit. When that happens, we bail out and reuse
the current props.
But it makes more sense to always set pendingProps to whatever the next
props will be. In other words, pendingProps is never null: it points to
either new props, or to the current props. Modeling it this way lets us
delete lots of code branches and is easier to reason about bail outs:
just compare the pending props to the current props.
API for batching top-level updates and deferring the commit.
- `root.createBatch` creates a batch with an async expiration time
associated with it.
- `batch.render` updates the children that the batch renders.
- `batch.then` resolves when the root has completed.
- `batch.commit` synchronously flushes any remaining work and commits.
No two batches can have the same expiration time. The only way to
commit a batch is by calling its `commit` method. E.g. flushing one
batch will not cause a different batch to also flush.
* Move ReactFiberTreeReflection to react-reconciler/reflection #11659
* Use * for react-reconciler
We don't know the latest local version, and release script currently doesn't bump deps automatically.
* Remove unused field
* Use CommonJS in entry point for consistency
* Undo the CommonJS change
I didn't realize it would break the build.
* Record sizes
* Remove reconciler fixtures
They're unnecessary now that we run real tests on reconciler bundles.
* Add rule to ignore default handling of not linting hidden files
* Undo changes
* Add function to validate warnings
* Use validateWarnings when reporting linc command
* Restore files
* Contain code to line file
* Add bundle linting and tests to the release script
- add yarn lint-build
- use yarn lint-build in circle ci build.sh
- add yarn lint-build, yarn test-prod, yarn test-build, and yarn test-build-prod to the realse script
* Improve readability of release test messages
* Run prettier
* Updating package versions for release 16.2.0
* Seperate bundle specific tests
- Moved the runYarnTask into utils since its being used two files now
- Uncomment out checks I mistakenly committed
* Revert a bunch of version bump changes
Mistakenly commited by release script
* .js for consistency
* KeyboardEvent interface-keypress
* Pass first 6 tests
* Roll getEventCharCode-test into SyntheticKeyboardEvent-test
* Run SyntheticKeyboardEvent-test on bundles
* Remove unused code
* Use only public API for ChangeEventPlugin-test.js
* precommit commands complete
* Removed comments
* Improving event dispatchers
* Updated tests
* Fixed for revisions
* Prettified
* Add more details and fixes to tests
* Not internal anymore
* Remove unused code
* added verification check for misspelled propTypes
* added flag to check if misspelled warning was shown to developer before
* added the condition to else if and improved the warning message
* moved variable under dev section & initialized it to false
* added test to confirm the missmatch prop type warning in both and tests files
* removed eslint disable and split error into 2 lines
* changed expectDev to expect in tests
* added __DEV__ condition before both tests
* Rename escapeText util. Test quoteAttributeValueForBrowser through ReactDOMServer API
* Fix lint errors
* Prettier reformatting
* Change syntax to prevent prettier escape doble quote
* Name and description gardening. Add tests for escapeTextForBrowser. Add missing tests
* Improve script tag as text content test
* Update escapeTextForBrowser-test.js
* Update quoteAttributeValueForBrowser-test.js
* Simplify tests
* Move utilities to server folder
* Extract Jest config into a separate file
* Refactor Jest scripts directory structure
Introduces a more consistent naming scheme.
* Add yarn test-bundles and yarn test-prod-bundles
Only files ending with -test.public.js are opted in (so far we don't have any).
* Fix error decoding for production bundles
GCC seems to remove `new` from `new Error()` which broke our proxy.
* Build production version of react-noop-renderer
This lets us test more bundles.
* Switch to blacklist (exclude .private.js tests)
* Rename tests that are currently broken against bundles to *-test.internal.js
Some of these are using private APIs. Some have other issues.
* Add bundle tests to CI
* Split private and public ReactJSXElementValidator tests
* Remove internal deps from ReactServerRendering-test and make it public
* Only run tests directly in __tests__
This lets us share code between test files by placing them in __tests__/utils.
* Remove ExecutionEnvironment dependency from DOMServerIntegrationTest
It's not necessary since Stack.
* Split up ReactDOMServerIntegration into test suite and utilities
This enables us to further split it down. Good both for parallelization and extracting public parts.
* Split Fragment tests from other DOMServerIntegration tests
This enables them to opt other DOMServerIntegration tests into bundle testing.
* Split ReactDOMServerIntegration into different test files
It was way too slow to run all these in sequence.
* Don't reset the cache twice in DOMServerIntegration tests
We used to do this to simulate testing separate bundles.
But now we actually *do* test bundles. So there is no need for this, as it makes tests slower.
* Rename test-bundles* commands to test-build*
Also add test-prod-build as alias for test-build-prod because I keep messing them up.
* Use regenerator polyfill for react-noop
This fixes other issues and finally lets us run ReactNoop tests against a prod bundle.
* Run most Incremental tests against bundles
Now that GCC generator issue is fixed, we can do this.
I split ErrorLogging test separately because it does mocking. Other error handling tests don't need it.
* Update sizes
* Fix ReactMount test
* Enable ReactDOMComponent test
* Fix a warning issue uncovered by flat bundle testing
With flat bundles, we couldn't produce a good warning for <div onclick={}> on SSR
because it doesn't use the event system. However the issue was not visible in normal
Jest runs because the event plugins have been injected by the time the test ran.
To solve this, I am explicitly passing whether event system is available as an argument
to the hook. This makes the behavior consistent between source and bundle tests. Then
I change the tests to document the actual logic and _attempt_ to show a nice message
(e.g. we know for sure `onclick` is a bad event but we don't know the right name for it
on the server so we just say a generic message about camelCase naming convention).
* Remove global mocks
They are making it harder to test compiled bundles.
One of them (FeatureFlags) is not used. It is mocked in some specific test files (and that's fine).
The other (FiberErrorLogger) is mocked to silence its output. I'll look if there's some other way to achieve this.
* Add error.suppressReactErrorLogging and use it in tests
This adds an escape hatch to *not* log errors that go through React to the console.
We will enable it for our own tests.
* Create test to verify ReactShallowRenderer bug (#11496)
* Fix ReactShallowRenderer callback bug on componentWillMount (#11496)
* Improve fnction naming and clean up queued callback before call
* Run prettier on ReactShallowRenderer.js
* Consolidate callback call on ReactShallowRenderer.js
* Ensure callback behavior is similar between ReactDOM and ReactShallowRenderer
* Fix Code Review requests (#11507)
* Move test to ReactCompositeComponent
* Verify the callback gets called
* Ensure multiple callbacks are correctly handled on ReactShallowRenderer
* Ensure the setState callback is called inside componentWillMount (ReactDOM)
* Clear ReactShallowRenderer callback queue before actually calling the callbacks
* Add test for multiple callbacks on ReactShallowRenderer
* Ensure the ReactShallowRenderer callback queue is cleared after invoking callbacks
* Remove references to internal fields on ReactShallowRenderer test
* Move Jest setup files to /dev/ subdirectory
* Clone Jest /dev/ files into /prod/
* Move shared code into scripts/jest
* Move Jest config into the scripts folder
* Fix the equivalence test
It fails because the config is now passed to Jest explicitly.
But the test doesn't know about the config.
To fix this, we just run it via `yarn test` (which includes the config).
We already depend on Yarn for development anyway.
* Add yarn test-prod to run Jest with production environment
* Actually flip the production tests to run in prod environment
This produces a bunch of errors:
Test Suites: 64 failed, 58 passed, 122 total
Tests: 740 failed, 26 skipped, 1809 passed, 2575 total
Snapshots: 16 failed, 4 passed, 20 total
* Ignore expectDev() calls in production
Down from 740 to 175 failed.
Test Suites: 44 failed, 78 passed, 122 total
Tests: 175 failed, 26 skipped, 2374 passed, 2575 total
Snapshots: 16 failed, 4 passed, 20 total
* Decode errors so tests can assert on their messages
Down from 175 to 129.
Test Suites: 33 failed, 89 passed, 122 total
Tests: 129 failed, 1029 skipped, 1417 passed, 2575 total
Snapshots: 16 failed, 4 passed, 20 total
* Remove ReactDOMProduction-test
There is no need for it now. The only test that was special is moved into ReactDOM-test.
* Remove production switches from ReactErrorUtils
The tests now run in production in a separate pass.
* Add and use spyOnDev() for warnings
This ensures that by default we expect no warnings in production bundles.
If the warning *is* expected, use the regular spyOn() method.
This currently breaks all expectDev() assertions without __DEV__ blocks so we go back to:
Test Suites: 56 failed, 65 passed, 121 total
Tests: 379 failed, 1029 skipped, 1148 passed, 2556 total
Snapshots: 16 failed, 4 passed, 20 total
* Replace expectDev() with expect() in __DEV__ blocks
We started using spyOnDev() for console warnings to ensure we don't *expect* them to occur in production. As a consequence, expectDev() assertions on console.error.calls fail because console.error.calls doesn't exist. This is actually good because it would help catch accidental warnings in production.
To solve this, we are getting rid of expectDev() altogether, and instead introduce explicit expectation branches. We'd need them anyway for testing intentional behavior differences.
This commit replaces all expectDev() calls with expect() calls in __DEV__ blocks. It also removes a few unnecessary expect() checks that no warnings were produced (by also removing the corresponding spyOnDev() calls).
Some DEV-only assertions used plain expect(). Those were also moved into __DEV__ blocks.
ReactFiberErrorLogger was special because it console.error()'s in production too. So in that case I intentionally used spyOn() instead of spyOnDev(), and added extra assertions.
This gets us down to:
Test Suites: 21 failed, 100 passed, 121 total
Tests: 72 failed, 26 skipped, 2458 passed, 2556 total
Snapshots: 16 failed, 4 passed, 20 total
* Enable User Timing API for production testing
We could've disabled it, but seems like a good idea to test since we use it at FB.
* Test for explicit Object.freeze() differences between PROD and DEV
This is one of the few places where DEV and PROD behavior differs for performance reasons.
Now we explicitly test both branches.
* Run Jest via "yarn test" on CI
* Remove unused variable
* Assert different error messages
* Fix error handling tests
This logic is really complicated because of the global ReactFiberErrorLogger mock.
I understand it now, so I added TODOs for later.
It can be much simpler if we change the rest of the tests that assert uncaught errors to also assert they are logged as warnings.
Which mirrors what happens in practice anyway.
* Fix more assertions
* Change tests to document the DEV/PROD difference for state invariant
It is very likely unintentional but I don't want to change behavior in this PR.
Filed a follow up as https://github.com/facebook/react/issues/11618.
* Remove unnecessary split between DEV/PROD ref tests
* Fix more test message assertions
* Make validateDOMNesting tests DEV-only
* Fix error message assertions
* Document existing DEV/PROD message difference (possible bug)
* Change mocking assertions to be DEV-only
* Fix the error code test
* Fix more error message assertions
* Fix the last failing test due to known issue
* Run production tests on CI
* Unify configuration
* Fix coverage script
* Remove expectDev from eslintrc
* Run everything in band
We used to before, too. I just forgot to add the arguments after deleting the script.
* support Call and Return components in React.Children calls
* make tests more verbose
* fix ordering of React component types
* cleanup conditional detection of children type
* directly inline callback invocation
* reduce callback invocation code re-use
* Forked ReactFeatureFlags for React Native to enable debugRenderPhaseSideEffects GK
* Changed debugRenderPhaseSideEffects in www feature flags to be runtime as well
* generate synthetics events using public API
* rewritten createEvent to use public APIs
* removed all references SyntheticEvent.release
In order to test under realistic circumstances I had to move
the expectations into a callback in mosts tests to overcome
the effects of event pooling.
* run prettier
* remove empty line
* don't use ReactTestUtils
* run prettier and fix linter issues
* remove duplicate test
* remove invalid calls to expect
The removed `expect` calls verified the correct behaviour based on
missing `preventDefault` and `stopPropagation` methods.
The was correct as we used plain objects to simulate events.
Since we switched to the public API we're using native events which
do have these methods.
* set event.defaultPrevented to undefined
This was missed when the test was first migrated.
When emulating IE8 not only has returnValue to be false.
In addition defaultPrevented must not be defined.
* run all tests and format code
* rename instance variable to node
* remove backtick
* only simulate IE in normalisation test
* include assignment in definition
* add missing `persist` test
* use method instead of field to prevent default
* expect properties to be unchanged on persisted event
* optimise tests that deal with event persitence
* declare and assign `event` on the same line if not reassigned later
The `wheel` event has not always been supported in every browser. React would fall back to `mousewheel` and `DOMMouseScroll` when the `wheel` event was not available. All supported browsers provide the `wheel` event. This code is no longer necessary.
Fixes a case where changing the name and checked value of a radio button in the same update would lead to checking the wrong radio input. Also adds a DOM test fixture for related issue.
Related issues:
https://github.com/facebook/react/issues/7630
* Use const/let in more places (#11467)
* Convert ReactDOMFiberTextarea to const/let
* Convert ReactDOMSelection to const/let
* Convert setTextContent to const/let
* Convert validateDOMNesting to const/let
* Replace Object.assign by Object Spread
* Convert ReactDOMFiberOption to Object Spread
* Convert ReactDOMFiberTextarea to Object Spread
* Convert validateDOMNesting to Object Spread
* Improve formatting of errors when building
* Remove undefined from the header when error.plugin is undefined
* Add babel-code-frame and syntax highlighting in error message
* Run yarn prettier and fix code format
* Rewrite ReactDOMComponentTree-test to test behavior using Public API
- Part of #11299
- I've tried to identify cases where code within ReactDOMComponentTree is exercised and have updated accordingly but I'm not entirely sure whether I'm on the right track. I thought I'd PR to get feedback from the community. Looking forward to comments.
* Prettier and lint changes
* Remove testing of internals and add test cases for testing behavior exhibited after use of getInstanceFromNode
* [RFC] Update testing approach to verify exhibited behavior dependent upon methods in ReactDOMComponentTree
* Remove tests from event handlers and use sync tests
* Prettier changes
* Rename variables to be more semantic
* Prettier updates
* Update test following review
- Use beforeEach and afterEach to set up and tear down container element for use in each test
- Move any functions specific to one test to within test body (improves readability imo)
* Add coverage for getNodeFromInstance and implementation of getFiberCurrentPropsFromNode
- After researching usage of getNodeFromInstance we can test getNodeFromInstance dispatching some events and asserting the id of the currentTarget
- After checking git blame for getFiberCurrentPropsFromNode and reading through #8607 I found a test that we can simplify to assert behavior of the function by ensuring event handler props are updated from the fiber props. Swapping out the implementation of this function with `return node[internalInstanceKey].memoizedProps` results in a failure.
When we're rendering work at a specific level, and a higher priority
update comes in, we interrupt the current work and restart at the
higher priority. The rationale is that the high priority update is
likely cheaper to render that the lower one, so it's usually worth
throwing out the current work to get the high pri update on the screen
as soon as possible.
Currently, we also interrupt the current work if an update of *equal*
priority is scheduled. The rationale here is less clear: the only reason
to do this is if both updates are expected to flush at the same time,
to prevent tearing. But this usually isn't the case. Separate setStates
are usually distinct updates that can be flushed separately, especially
if the components that are being updated are in separate subtrees.
An exception is in Flux-like systems where multiple setStates are the
result of a single conceptual update/event/dispatch. We can add an
explicit API for batching in the future; in fact, we'd likely need one
anyway to account for expiration accidentally causing consecutive
updates to fall into separate buckets.
* Don't call idle callback unless there's time remaining
* Expiration fixture
Fixture that demonstrates how async work expires after a certain interval.
The fixture clogs the main thread with animation work, so it only works if the
`timeout` option is provided to `requestIdleCallback`.
* Pass timeout option to requestIdleCallback
Forces `requestIdleCallback` to fire if too much time has elapsed, even if the
main thread is busy. Required to make expiration times work properly. Otherwise,
async work can expire, but React never has a chance to flush it because the
browser never calls into React.
Fixes an issue where performWorkOnRoot was called, but nextFlushedRoot
was not set. This happened in a special branch where we synchronously
flush newly mounted DOM trees outside the normal work loop.
Arguably, performWorkOnRoot should read from the globally assigned root
and expiration time instead of accepting arguments, since those
arguments are expected to be the same as the global values, anyway. I
decided against that since the global values could be null, so reading
from them would require extra null checks.
* Unfreeze the react-dom/server interface
this allows stubbing of the exposed named functions, as was possible before v16.1
fixes#11526
* Fix missing version export
* Fix missing version export
* Whitespace
* Update Flow
* Fix createElement() issue
The * type was too ambiguous. It's always a string so what's the point?
Suppression for missing Flow support for {is: ''} web component argument to createElement() didn't work for some reason.
I don't understand what the regex is testing for anyway (a task number?) so I just removed that, and suppression got fixed.
* Remove deleted $Abstract<> feature
* Expand the unsound isAsync check
Flow now errors earlier because it can't find .type on a portal.
* Add an unsafe cast for the null State in UpdateQueue
* Introduce "hydratable instance" type
The Flow error here highlighted a quirk in our typing of hydration.
React only really knows about a subset of all possible nodes that can
exist in a hydrated tree. Currently we assume that the host renderer
filters them out to be either Instance or TextInstance. We also assume
that those are different things which they might not be. E.g. it could
be fine for a renderer to render "text" as the same type as one of the
instances, with some default props.
We don't really know what it will be narrowed down to until we call
canHydrateInstance or canHydrateTextInstance. That's when the type is
truly refined.
So to solve this I use a different type for hydratable instance that is
used in that temporary stage between us reading it from the DOM and until
it gets refined by canHydrate(Text)Instance.
* Have the renderer refine Hydratable Instance to Instance or Text Instance
Currently we assume that if canHydrateInstance or canHydrateTextInstance
returns true, then the types also match up. But we don't tell that to Flow.
It just happens to work because `fiber.stateNode` is still `any`.
We could potentially use some kind of predicate typing but instead
of that I can just return null or instance from the "can" tests.
This ensures that the renderer has to do the refinement properly.
* Use dispatchEvent() directly
Don't fear repetition in tests. It is clearer what's going on.
* Clean up the container after tests
* Add a comment to container code
* Update SyntheticWheelEvent tests to use public API
* Replace: ReactTestUtils.SimulateNative to native Events()
* Update: Replaced WheelEvent() interface to document.createEvent
* Fix: Lint SyntheticWheelEvent file
* Update: Custom WheelEvent function to a generic MouseEvent function
* Update: Prettier SyntheticWheelEvent-test.js
* Verify the `button` property is set on synthetic event
* Use MouseEvent constructor over custom helper
* Rewrite to test React rather than jsdom
* Force the .srcElement code path to execute
* Style tweaks and slight code reorganization
* Refactor SyntheticClipboardEvent tests to only use the public API
* Replace local document creation by document body reset on each test case execution
* Set up and tear down container separately
* Tweak test assertion logic for clarity
* Remove simulate abstraction and create events directly
* Ensure the test covers IE8 behavior
* Verify that persistence works
**what is the change?:**
Adding a document linking to the Facebook Open Source Code of Conduct,
for visibility and to meet Github community standards.
**why make this change?:**
Facebook Open Source provides a Code of Conduct statement for all
projects to follow.
React already links to this Code of Conduct in the README, which is
great!
Exposing the COC via a separate markdown file is a standard being
promoted by Github via the Community Profile in order to meet their Open
Source Guide's recommended community standards.
As you can see, adding this file will complete [React's Community Profile](https://github.com/facebook/react/community)
checklist and increase the visibility of our COC.
**test plan:**
Viewing it on my branch -
(Flarnie will insert screenshot)
**issue:**
internal task t23481323
* Measure time between scheduling an async callback and flushing it
Helps detect starvation issues.
* Debug comments should print directly above the next measure
* Better warning message
Most users won't know what "expires" means
* Remove inputValueTracking from ReactDOMComponent-test dependency
* prettier
* use node._valueTracker and add some test cases to make sure that value being tracked
* using Object.getOwnPropertyDescriptor to get the tracked value
* move getValueTracker to each test case and use its corresponding prototype
* remove tests and move the value tracker definition before React is imported
* Delete these tests completely
* Added missing params object to execUnlessDry call
* Public package names are no longer hard-coded
* Added "v" prefix to git tag
* Show more accurate in-progress duration
* Properly bucket-bridage params
* Prettier
* Publish command logs stack with error
* Consolidate build process with GCC
* Record sizes
* Refactor header and footer wrapping
It is easier to understand if we just explicitly type them out.
* Add a timeout before querying npm right after publish
* Conditionally log some post publish steps
* Print ready-to-paste 'yarn add' instructions for CRA prerelease testing
* Add a failing test for createFactory in production
* Fix createFactory() in production
* Add more prod-only tests
* Fix prettier
* Run prettier 1.8.1
* Enable User Timing API integration with a feature flag
* Expose a way to toggle user timing flag in www
* Update ReactNativeCSFeatureFlags.js
* Update ReactFeatureFlags.js
* Fix dead code elimination for feature flags
Turning flags into named exports fixes dead code elimination.
This required some restructuring of how we verify that flag types match up. I used the Check<> trick combined with import typeof, as suggested by @calebmer.
For www, we can no longer re-export `require('ReactFeatureFlags')` directly, and instead destructure it. This means flags have to be known at init time. This is already the case so it's not a problem. In fact it may be better since it removes extra property access in tight paths.
For things that we *want* to be dynamic on www (currently, only performance flag) we can export a function to toggle it, and then put it on the secret exports. In fact this is better than just letting everyone mutate the flag at arbitrary times since we can provide, e.g., a ref counting interface to it.
* Record sizes
* Convert ReactDOM to const/let
* Convert ReactDOMComponentTree to const/let
* Convert ReactDOMComponentTree to const/let
* Convert getNodeForCharacterOffset to const/let
* Convert getTextContentAccessor to const/let
* Convert inputValueTracking to const/let
* Convert setInnerHTML to const/let
* Convert setTextContent to const/let
* Convert validateDOMNesting to const/let
* Convert EventPlugin{Hub,Registry} to named exports
* Convert EventPluginUtils to named exports
* Convert EventPropagators to named exports
* Convert ReactControlledComponent to named exports
* Convert ReactGenericBatching to named exports
* Convert ReactDOMComponentTree to named exports
* Convert ReactNativeComponentTree to named exports
* Convert ReactNativeRTComponentTree to named exports
* Convert FallbackCompositionState to named exports
* Convert ReactEventEmitterMixin to named exports
* Convert ReactBrowserEventEmitter to named exports
* Convert ReactNativeEventEmitter to named exports
* Convert ReactDOMEventListener to named exports
* Convert DOMMarkupOperations to named exports
* Convert DOMProperty to named exports
* Add suppression for existing Flow violation
Flow didn't see it before.
* Update sizes
* Rewrite setInnerHTML tests to use Public API.
* Rename variables and drop unnecessary variable assignments.
* Rename testfile to dangerouslySetInnerHTML-test.js
* Properly prettify test file.
* Rewrite SVG tests to verify we recover from missing innerHTML
* Use only public api for ReactDOMEventListener-test.js
* Use less confusing naming
There was no need to extract React elements into separate variables.
* Replace the "disappearance" test
I could not get it to fail on master so it was probably testing something specific to Stack implementation details. It was also already broken because it didn't look at the right argument and never actually called `unmountComponentAtNode`.
Instead I replaced it with original repro case from https://github.com/facebook/react/issues/1105 which is when it was introduced.
* Tweak naming and add comments
* Missed this one
* Use only public API for EnterLeaveEventPlugin Tests (#11299)
* Trigger native event to test EnterLeaveEventPlugin (#11299)
* Rewrite EnterLeaveEventPlugin tests to use dispatchEvent
* Update EnterLeaveEventPlugin test to use OnMouseLeave event
* Add coverage for onMouseEnter too
* Update transforms to handle ES modules
* Update Jest to handle ES modules
* Convert react package to ES modules
* Convert react-art package to ES Modules
* Convert react-call-return package to ES Modules
* Convert react-test-renderer package to ES Modules
* Convert react-cs-renderer package to ES Modules
* Convert react-rt-renderer package to ES Modules
* Convert react-noop-renderer package to ES Modules
* Convert react-dom/server to ES modules
* Convert react-dom/{client,events,test-utils} to ES modules
* Convert react-dom/shared to ES modules
* Convert react-native-renderer to ES modules
* Convert react-reconciler to ES modules
* Convert events to ES modules
* Convert shared to ES modules
* Remove CommonJS support from transforms
* Move ReactDOMFB entry point code into react-dom/src
This is clearer because we can use ES imports in it.
* Fix Rollup shim configuration to work with ESM
* Fix incorrect comment
* Exclude external imports without side effects
* Fix ReactDOM FB build
* Remove TODOs I don’t intend to fix yet
* Constructor test and fix complete
* Linters and prettier run
* Remove unnecessary checks
* Update error message
* Updat unit test
* prettier
* Tweak the check to be more specific
* Move tests to ReactCompositeComponent-test
* add error call count and remove line
* Remove prop-types/checkPropTypes reimplementation
* Remove renderer dependency on top-level PropTypes
This annotation is unnecessary because we already warn for bad event listener types.
* Record sizes
* Drop fbjs/lib/EventListener from tests
Assert on the underlying native event listener instead.
This test file still needs to be rewritten in terms of public APIs.
* Inline fbjs/lib/EventListener dependency
We explicitly don't want to shim this and we don't use the return value.
We can probably even drop the IE path now since we don't support it.
Not sure if that'll be a true breaking change though.
* Wrap event listeners and the callback passed to requestIdleCallback
This is a FBism.
This uses the injection model in ReactErrorUtils. This isn't technically
going to used for errors but close enough.
This really wants to be eager but we can't because of dynamic injection.
* move to pendingProps to args
* update userFiber in ReactChildFiber
* prettier it
* prettier it
* move expirationTime to the last
* move expirationTime to the last on userFiber
* Move assignment
* Deduplicated many warnings (#11140)
* Deduplicated the following warnings:
1. Can only update a mounted or mounting component.
This usually means you called setState, replaceState,
or forceUpdate on an unmounted component. This is a no-op
2. %s.componentWillReceiveProps(): Assigning directly to
this.state is deprecated (except inside a component's
constructor). Use setState instead.'
3. An update (setState, replaceState, or forceUpdate) was scheduled
from inside an update function. Update functions should be pure,
with zero side-effects. Consider using componentDidUpdate or a
callback.
4. setState(...): Cannot call setState() inside getChildContext()
* Code review changes made for #11140
* Minor style fix
* Test deduplication for noop updates in server renderer
* Test deduplication for cWRP warning
* Test deduplication for cWM setState warning
* Test deduplication for unnmounted setState warning
* Fix existing Flow typing
* Test deduplication for invalid updates
* Test deduplication of update-in-updater warning
* Corrects error message for select with props.multiple set to true and a null value.
* Don't bother deduplicating based on type
* Make the code a bit simpler (and more verbose)
* Add Fragment as a named export to React
* Remove extra tests for Fragment
* Change React.Fragment export to be a string '#fragment'
* Fix fragment special case to work with 1 child
* Add single child test for fragment export
* Move fragment definition to ReactEntry.js and render components for key warning tests
* Inline createFiberFromElementType into createFiberFromElement
* Update reconciliation to special case fragments
* Use same semantics as implicit childsets for ReactFragment
* Add more fragment state preservation tests
* Export symbol instead of string for fragments
* Fix rebase breakages
* Re-apply prettier at 1.2.2
* Merge branches in updateElement
* Remove unnecessary check
* Re-use createFiberFromFragment for fragment case
* Simplyify branches by adding type field to fragment fiber
* Move branching logic for fragments to broader methods when possible.
* Add more tests for fragments
* Address Dan's feedback
* Move REACT_FRAGMENT_TYPE into __DEV__ block for DCE
* Change hex representation of REACT_FRAGMENT_TYPE to follow convention
* Remove unnecessary branching and isArray checks
* Update test for preserving children state when keys are same
* Fix updateSlot bug and add more tests
* Make fragment tests more robust by using ops pattern
* Update jsx element validator to allow numbers and symbols
* Remove type field from fragment fiber
* Fork reconcileChildFibers instead of recursing
* Use ternary if condition
* Revamp fragment test suite:
- Add more coverage to fragment tests
- Use better names
- Remove useless Fragment component inside tests
- Remove useless tests so that tests are more concise
* Check output of renderer in fragment tests to ensure no silly business despite states being preserved
* Finish implementation of fragment reconciliation with desired behavior
* Add reverse render direction for fragment tests
* Remove unneeded fragment branch in updateElement
* Add more test cases for ReactFragment
* Handle childless fragment in reconciler
* Support fragment flattening in SSR
* Clean up ReactPartialRenderer
* Warn when non-key and children props are passed to fragments
* Add non-null key check back to updateSlot's array's case
* Add test for positional reconciliation in fragments
* Add warning for refs in fragments with stack trace
* Implement CS first take
This is using a pure JS API. This should probably switch to native hooks
at some later point but I'll start ironing out issues at this level first.
* Use async scheduling by default
The scheduled callback gets called immediately in render with infinite
time for now. Later this will be per root and abortable.
* Fix up the type signature of the ReactNativeCSType export
* Add escape hatch for special cased children
Working around the fact that we can't map arbitrary children slots. Just
the "children" prop.
* Readd providesModule for ReactNativeCSTypes
* Fix lint
* Fix ReactNativeTypes providesModule and CI check
* Special case a parent instance that doesn't have a props object
CSCustom can be anything here. Ugly but whatevs.
* Don't forget to store stateUpdater so that we can trigger updates
* Fix test
* Rewrite tests depending on internal API
* Remove focus being called when there was no blur event function before
* Remove triggering function and just let ReactTestUtils take care
* Use native events
* Remove duplicate
* Simulate native event when changing value on reentrant
* Change wasn't being called
* Use Simulate only
* Use React event handlers on test
* Move commentary
* Lint commit
* Use native event
* Comment native event dispatching
* Prettier
* add setUntrackedValue
* Prettier-all
* Use dispatchEvent instead of ReactTestUtils Simulates;
* Prettier
* Fix lint
* Remove useless arg
* Wrap event dispatcher into function
* Remove deprecated Event
* Remove unused change event dispatcher
* Fix merge
* Prettier
* Add missing focus/blur calls
They are necessary to cover for the fix in #8240.
While refactoring root scheduler, I noticed we have few tests that
cover updates across multiple roots. To address, I've added multiple
root cases to the fuzz tester.
Includes a hard-coded test case that was failing before #11307 landed.
* Update Jest
* Remove hacks for Jest + Workspace integration
They were fixed by https://github.com/facebook/jest/pull/4761.
* Use relative requires in tests relying on private APIs
I changed them to absolute to work around a Jest bug.
The bug has been fixed so I can revert my past changes now.
* Remove Task priority
The concept of Task priority was originally added as a way to avoid
reentrancy. Sync priority is for work that flushes synchronously, and
Task is for work that flushes at the end of the event loop.
But it turns out that in most cases, it's simpler to model Task and
Sync as the same priority level. For example, it's never correct to
flush Sync work from the update queue without flushing Task. Doing so
can lead to infinite update loops.
And using a separate priority level is not necessary to avoid
reentrancy. We already track when work is being rendered, and exit
before entering the render cycle again. That alone is sufficient.
This commit removes Task priority from the codebase. Now we use the
same level for both truly synchronous work and work that is deferred
until the end of the event loop.
This also enables us to remove DOM-specific legacy cases from the
reconciler and lift them to the renderer.
* Remove isUnbatched from FiberRoot
Simpler to render unbatched roots immediately.
* Use a cyclic linked list for root schedule
Avoids the need for a separate `isScheduled` field.
* Added an automated test that would have caught the recent error code transform bug
* Renamed dev-expression-with-codes test to replace-invariant-error-codes
* Formatting nit
* Use relative paths in packages/react
* Use relative paths in packages/react-art
* Use relative paths in packages/react-cs
* Use relative paths in other packages
* Fix as many issues as I can
This uncovered an interesting problem where ./b from package/src/a would resolve to a different instantiation of package/src/b in Jest.
Either this is a showstopper or we can solve it by completely fobbidding remaining /src/.
* Fix all tests
It seems we can't use relative requires in tests anymore. Otherwise Jest becomes confused between real file and symlink.
https://github.com/facebook/jest/issues/3830
This seems bad... Except that we already *don't* want people to create tests that import individual source files.
All existing cases of us doing so are actually TODOs waiting to be fixed.
So perhaps this requirement isn't too bad because it makes bad code looks bad.
Of course, if we go with this, we'll have to lint against relative requires in tests.
It also makes moving things more painful.
* Prettier
* Remove @providesModule
* Fix remaining Haste imports I missed earlier
* Fix up paths to reflect new flat structure
* Fix Flow
* Fix CJS and UMD builds
* Fix FB bundles
* Fix RN bundles
* Prettier
* Fix lint
* Fix warning printing and error codes
* Fix buggy return
* Fix lint and Flow
* Use Yarn on CI
* Unbreak Jest
* Fix lint
* Fix aliased originals getting included in DEV
Shouldn't affect correctness (they were ignored) but fixes DEV size regression.
* Record sizes
* Fix weird version in package.json
* Tweak bundle labels
* Get rid of output option by introducing react-dom/server.node
* Reconciler should depend on prop-types
* Update sizes last time
* Split performWork into renderRoot and commitRoot
It turns out that the scheduler is too coupled to how the DOM renderer
works. Specifically, the requestIdleCallback model, and how roots are
committed immediately after completing. Other renderers have different
constraints for when to yield and when to commit work.
We're moving towards a model where the scheduler only works on a single
root at a time, and the render phase and commit phase are split into
distinct entry points. This gives the renderer more control over when
roots are committed, coordinating multiple roots, deferring the commit
phase, batching updates, when to yield execution, and so on.
In this initial commit, I've left the renderers alone and only changed
the scheduler. Mostly, this involved extracting logic related to
multiple roots and moving it into its own section at the bottom of the
file. The idea is that this section can be lifted pretty much as-is
into the renderers. I'll do that next.
* Remove FiberRoot scheduleAt
Isn't actually used anywhere
* Make the root schedule a linked list again
Since this still lives inside the renderer, let's just use the
FiberRoot type. The FiberRoot concept will likely be lifted out
eventually, anyway.
* commitRoot should accept a HostRoot
This way it's less reliant on the alternate model
* Unify branches
* Remove dead branch
onUncaughtError is only called while we're working on a root.
* remainingWork -> remainingExpirationTime
I was wary of leaking NoWork but mixing numbers and null is worse so
let's just do it until we think of something better.
* Rename stuff
While testing some changes to RN, I noticed that the '--sync-fbsource' flag had been broken recently by things being moved around and the newly-added CS renderer. Fixed it up.
* react-dom/src/syntheticEvents => events, and put plugins into it
* Flatten react-dom/src/shared
* Split react-dom/src/client/utils into event/ and root client folder
Makes it clearer what is used by what.
* Strictly separate modules that can be imported by client and server
* shared/src -> shared
It's not a real package and doesn't even have package.json.
This will also make importing less weird if we drop Haste.
* Get rid of shared/utils
Moved event-specific into shared/event.
Moved rest to the root since distinction has always been pretty arbitrary.
* Fix references to old shared/src paths
* Move files and tests to more meaningful places
* Fix the build
Now that we import reconciler via react-reconciler, I needed to make a few tweaks.
* Update sizes
* Move @preventMunge directive to FB header
* Revert unintentional change
* Fix Flow coverage
I forgot to @flow-ify those files. This uncovered some issues.
* Prettier, I love you but you're bringing me down
Prettier, I love you but you're bringing me down
Like a rat in a cage
Pulling minimum wage
Prettier, I love you but you're bringing me down
Prettier, you're safer and you're wasting my time
Our records all show you were filthy but fine
But they shuttered your stores
When you opened the doors
To the cops who were bored once they'd run out of crime
Prettier, you're perfect, oh, please don't change a thing
Your mild billionaire mayor's now convinced he's a king
So the boring collect
I mean all disrespect
In the neighborhood bars I'd once dreamt I would drink
Prettier, I love you but you're freaking me out
There's a ton of the twist but we're fresh out of shout
Like a death in the hall
That you hear through your wall
Prettier, I love you but you're freaking me out
Prettier, I love you but you're bringing me down
Prettier, I love you but you're bringing me down
Like a death of the heart
Jesus, where do I start?
But you're still the one pool where I'd happily drown
And oh! Take me off your mailing list
For kids who think it still exists
Yes, for those who think it still exists
Maybe I'm wrong and maybe you're right
Maybe I'm wrong and maybe you're right
Maybe you're right, maybe I'm wrong
And just maybe you're right
And oh! Maybe mother told you true
And there'll always be somebody there for you
And you'll never be alone
But maybe she's wrong and maybe I'm right
And just maybe she's wrong
Maybe she's wrong and maybe I'm right
And if so, here's this song!
* Include component stack in more places, including SSR
* Forbid including reconciler code into the server bundle
* Tighten up the Flow annotation
* Fix lint
* Gosh Prettier
* Only renderers should depend on reconciler code
* Remove react-art dependency on react-dom modules
They share ReactDOMFrameScheduling so I moved it to shared.
* Update build size
* [CS] Clone container instead of new root concept
The extra "root" concept is kind of unnecessary. Instead of having a
mutable container even in the persistent mode, I'll instead make the
container be immutable too and be cloned. Then the "commit" just becomes
swapping the previous container for the new one.
* Change the signature or persistence again
We may need to clone without any updates, e.g. when the children are changed.
Passing in the previous node is not enough to recycle since it won't have the
up-to-date props and children. It's really only useful to for allocation pooling.
* Implement persistent updates
This forks the update path for host fibers. For mutation mode we mark
them as having an effect. For persistence mode, we clone the stateNode with
new props/children.
Next I'll do HostRoot and HostPortal.
* Refine protocol into a complete and commit phase
finalizeContainerChildren will get called at the complete phase.
replaceContainer will get called at commit.
Also, drop the keepChildren flag. We'll never keep children as we'll never
update a container if none of the children has changed.
* Implement persistent updates of roots and portals
These are both "containers". Normally we rely on placement/deletion effects
to deal with insertions into the containers. In the persistent mode we need
to clone the container and append all the changed children to it.
I needed somewhere to store these new containers before they're committed
so I added another field.
* Commit persistent work at the end by swapping out the container
* Unify cloneOrRecycle
Originally I tried to make the recyclable instance nullable but Flow didn't
like that and it's kind of sketchy since the instance type might not be
nullable.
However, the real difference which one we call is depending on whether they
are equal. We can just offload that to the renderer. Most of them won't
need to know about this at all since they'll always clone or just create
new.
The ones that do know now have to be careful to compare them so they don't
reuse an existing instance but that's probably fine to simplify the
implementation and API.
* Add persistent noop renderer for testing
* Add basic persistent tree test
* Test bail out
This adds a test for bailouts. This revealed a subtle bug. We don't set the
return pointer when stepping into newly created fibers because there
can only be one. However, since I'm reusing this mechanism for persistent
updates, I'll need to set the return pointer because a bailed out tree
won't have the right return pointer.
* Test persistent text nodes
Found another bug.
* Add persistent portal test
This creates a bit of an unfortunate feature testing in the unmount
branch.
That's because we want to trigger nested host deletions in portals in the
mutation mode.
* Don't consider container when determining portal identity
Basically, we can't use the container to determine if we should keep
identity and update an existing portal instead of recreate it. Because
for persistent containers, there is no permanent identity.
This makes it kind of strange to even use portals in this mode. It's
probably more ideal to have another concept that has permanent identity
rather than trying to swap out containers.
* Clear portals when the portal is deleted
When a portal gets deleted we need to create a new empty container and
replace the current one with the empty one.
* Add renderer mode flags for dead code elimination
* Simplify ReactNoop fix
* Add new type to the host config for persistent configs
We need container to stay as the persistent identity of the root atom.
So that we can refer to portals over time.
Instead, I'll introduce a new type just to temporarily hold the children
of a container until they're ready to be committed into the permanent
container. Essentially, this is just a fancy array that is not an array
so that the host can choose data structure/allocation for it.
* Implement new hooks
Now containers are singletons and instead their children swap. That way
portals can use the container as part of their identity again.
* Update build size and error codes
* Address comment
* Move new files to new location
* Enable Yarn workspaces for packages/*
* Move src/isomorphic/* into packages/react/src/*
* Create index.js stubs for all packages in packages/*
This makes the test pass again, but breaks the build because npm/ folders aren't used yet.
I'm not sure if we'll keep this structure--I'll just keep working and fix the build after it settles down.
* Put FB entry point for react-dom into packages/*
* Move src/renderers/testing/* into packages/react-test-renderer/src/*
Note that this is currently broken because Jest ignores node_modules,
and so Yarn linking makes Jest skip React source when transforming.
* Remove src/node_modules
It is now unnecessary. Some tests fail though.
* Add a hacky workaround for Jest/Workspaces issue
Jest sees node_modules and thinks it's third party code.
This is a hacky way to teach Jest to still transform anything in node_modules/react*
if it resolves outside of node_modules (such as to our packages/*) folder.
I'm not very happy with this and we should revisit.
* Add a fake react-native package
* Move src/renderers/art/* into packages/react-art/src/*
* Move src/renderers/noop/* into packages/react-noop-renderer/src/*
* Move src/renderers/dom/* into packages/react-dom/src/*
* Move src/renderers/shared/fiber/* into packages/react-reconciler/src/*
* Move DOM/reconciler tests I previously forgot to move
* Move src/renderers/native-*/* into packages/react-native-*/src/*
* Move shared code into packages/shared
It's not super clear how to organize this properly yet.
* Add back files that somehow got lost
* Fix the build
* Prettier
* Add missing license headers
* Fix an issue that caused mocks to get included into build
* Update other references to src/
* Re-run Prettier
* Fix lint
* Fix weird Flow violation
I didn't change this file but Flow started complaining.
Caleb said this annotation was unnecessarily using $Abstract though so I removed it.
* Update sizes
* Fix stats script
* Fix packaging fixtures
Use file: instead of NODE_PATH since NODE_PATH.
NODE_PATH trick only worked because we had no react/react-dom in root node_modules, but now we do.
file: dependency only works as I expect in Yarn, so I moved the packaging fixtures to use Yarn and committed lockfiles.
Verified that the page shows up.
* Fix art fixture
* Fix reconciler fixture
* Fix SSR fixture
* Rename native packages
Fixes a bug surfaced by www unit test.
I'm not yet sure the best way to test this; in the interest of landing
this fix quickly, I'll save the test for a follow-up.
* Add note to 'unreleased' CHANGELOG about deprecating Bower
**what is the change?:**
We will no longer release new versions of React to Bower, and we should
announce that as part of our CHANGELOG.
**why make this change?:**
We decided on this as a team.
**test plan:**
Visual inspection and spell check. :)
**issue:**
Just follow-up for https://github.com/facebook/react/pull/11223
* Improve messaging/formatting
* Move bower deprecation notice to top of changelog
* Delete tests that only mattered during createElement transition
They were added after #2576, but were only important when React.createElement was introduced as a migration path.
Now that elements are used consistently, these tests shouldn't be necessary.
I created a separate test specifically for scryRenderedComponentsWithType() though because that was the only one.
* Simplify mocking test setup
Today, the only remaining special behavior for Jest mocks is we let them render undefined.
We don't plan to introduce any other special behavior for them in the future.
(In fact, we already decided against replicating this special behavior for functional components.)
Therefore, we can remove dependency on Jest automocking mechanism in these tests completely,
and just explicitly mock the render method which is the only one for which we have special behavior.
For clarity, we add an explicit test for mockComponent() API (whose naming is a bit of a lie).
* Inline getTestDocument into test cases
* Remove mention of mock file we do not use
* Remove unused configuration entries
* Move eslint-rules package into the scripts/ folder
* ReactDOM.createRoot
Introduce new API for creating roots. Only root.render and root.unmount
are implemented. Later we'll add root.prerender, and support for lazy
roots (roots with DOM containers that resolve lazily).
* Add hydrate option to createRoot
* Deterministic updates
High priority updates typically require less work to render than
low priority ones. It's beneficial to flush those first, in their own
batch, before working on more expensive low priority ones. We do this
even if a high priority is scheduled after a low priority one.
However, we don't want this reordering of updates to affect the terminal
state. State should be deterministic: once all work has been flushed,
the final state should be the same regardless of how they were
scheduled.
To get both properties, we store updates on the queue in insertion
order instead of priority order (always append). Then, when processing
the queue, we skip over updates with insufficient priority. Instead of
removing updates from the queue right after processing them, we only
remove them if there are no unprocessed updates before it in the list.
This means that updates may be processed more than once.
As a bonus, the new implementation is simpler and requires less code.
* Fix ceiling function
Mixed up the operators.
* Remove addUpdate, addReplaceState, et al
These functions don't really do anything. Simpler to use a single
insertUpdateIntoFiber function.
Also splits scheduleUpdate into two functions:
- scheduleWork traverses a fiber's ancestor path and updates their
expiration times.
- scheduleUpdate inserts an update into a fiber's update queue, then
calls scheduleWork.
* Remove getExpirationTime
The last remaining use for getExpirationTime was for top-level async
updates. I moved that check to scheduleUpdate instead.
* Move UpdateQueue insertions back to class module
Moves UpdateQueue related functions out of the scheduler and back into
the class component module. It's a bit awkward that now we need to pass
around createUpdateExpirationForFiber, too. But we can still do without
addUpdate, replaceUpdate, et al.
* Store callbacks as an array of Updates
Simpler this way.
Also moves commitCallbacks back to UpdateQueue module.
* beginUpdateQueue -> processUpdateQueue
* Updates should never have an expiration of NoWork
* Rename expiration related functions
* Fix update queue Flow types
Gets rid of an unneccessary null check
* CS renderer
Because we didn't have enough RN experiments. I want to add one more.
* Split out hydration from the host config object
This makes it easier to do feature detection on the configuration.
* Move mutation host config to separate optional object
* Refs and life-cycles should happen even in immutable mode
* Unmount components even in non-mutation mode
This is the same as committing deletions but instead of finding host
components to delete, it only invokes componentWillUnmount and detaching
of refs.
* Add persistent updates API
This mode will use a clone based API instead of mutating host instances.
Needs implementation still.
It's awkward that there can be more than one child inserted into the root.
So we need a new API to create a "root" instance so that we can update it
atomically. Alternatively we could keep the mutable API for containers
and assume that most use cases would only have a single root.
* Package up CS renderer
* Fix reconciler package fixture
In sync mode, we downgrade sync priority work to task work when we're in
the commit phase, but not in the render phase. That means if you
schedule updates in both phases, the render phase update will flush
first, and the commit phase update will flush after that. What should
really happen is that both updates flush at the same time.
To solve this, updates in the commit phase are now given sync priority.
The distinction between task and sync really only exists to account for
a historical quirk in the behavior of top-level mounts. (Refer to the
test case titled "initial mount is sync inside batchedUpdates".)
Ideally, there would only be one priority for both sync and task. This
gets us closer to that model, while still accounting for
top-level mounts.
* chore(syntheticEvent): remove IE8 code
Since IE8 has been deprecated for a while, I thought it might be useful to remove some IE8-only code
If this is not something you want to focus on yet, or is too much work to test, feel free to close this PR
* Update SyntheticUIEvent.js
* Update SyntheticUIEvent.js
* remove unused require
* completely remove UIEvent
* augment with noop
everything breaks otherwise
* comment back
* spacing
Coalescing is the only feature that depends on PriorityLevel. Since
we're not sure if coalescing is even valuable, we'll remove it for
now. If it turns out we need it, we can add it back later.
* Initial commit of react-reconciler bundle
* I think it’s working 🙀
* React reconciler: slightly better description and README
* Drop react-reconciler version to an unstable release number
* Convert to moduleType enum and fix packaging
* eslint
* s/Renderer/Reconciler in docs
* yarn prettier
* change names of things in the react-reconciler readme
* change predicate
* rollup: flip object-assign shimming check
* copy noop renderer into react-reconciler fixture
* Change reconciler fixture test
* prettier
* Remove a bunch of Noop test renderer
* Delete a bunch of stuff we don’t care about for reconciler teesting. Add flow pragmas for future flow pragma testing
* Remove PATENTS
* Update Reconciler fixture docs
* ReactDOMUnstableNativeDependencies should be ISOMORPHIC
* Inline fixture renderer
* Make it "RENDERER"
* There is no UMD build. It also doesn't need propTypes.
* Tweak how the reconciler is built
* Record sizes
* Update README.md
* Keep autoFocus attribute in the DOM
* Don't emit autoFocus attribute on the client
* Test that hydration doesn't call focus
* Add autoFocus to SSR fixture
* Add <noscript> with HTML in it to SSR fixture
* Wrap <noscript> into a <div> to get its "client HTML"
* Revert "Wrap <noscript> into a <div> to get its "client HTML""
This reverts commit 27a42503e2790a0d5cf0b90451a664fc6ab9d862.
* Always use parent.ownerDocument
* Add failing iframe test
* Possible fix by returning null ownerName in SSR
* prettier
* eslolint
* gah c’mon really?
* emptyFunction.thatReturnsNull
* One less property access
* [Work-in-progress] Assign expiration times to updates
An expiration time represents a time in the future by which an update
should flush. The priority of the update is related to the difference
between the current clock time and the expiration time. This has the
effect of increasing the priority of updates as time progresses, to
prevent starvation.
This lays the initial groundwork for expiration times without changing
any behavior. Future commits will replace work priority with
expiration times.
* Replace pendingWorkPriority with expiration times
Instead of a priority, a fiber has an expiration time that represents
a point in the future by which it should render.
Pending updates still have priorities so that they can be coalesced.
We use a host config method to read the current time. This commit
implements everything except that method, which currently returns a
constant value. So this just proves that expiration times work the same
as priorities when time is frozen. Subsequent commits will show the
effect of advancing time.
* Triangle Demo should use a class
shouldComponentUpdate was removed from functional components.
Running the demo shows, now that expiration is enabled, the demo does
not starve. (Still won't run smoothly until we add back the ability to
resume interrupted work.)
* Use a magic value for task expiration time
There are a few cases related to sync mode where we need to distinguish
between work that is scheduled as task and work that is treated like
task because it expires. For example, batchedUpdates. We don't want to
perform any work until the end of the batch, regardless of how much
time has elapsed.
* Use current time to calculate expiration time
* Add unit tests for expiration and coalescing
* Delete unnecessary abstraction
* Move performance.now polyfill to ReactDOMFrameScheduling
* Add expiration to fuzz tester
* Expiration nits
- Rename Done -> NoWork
- Use max int32 instead of max safe int
- Use bitwise operations instead of Math functions
* Allow single `on` property for custom elements
* Remove test from ReactDOMComponent-test
* Allow custom attribute named 'on' to be passed
* Check property length instead of comparing strings
* Add a regression test for #10906
* Turn while conditions into breaks without changing the logic
This will be easier to follow when we add more code there.
* var => const/let
So that I can add a block scoped variable.
* Check alternates when comparing to the common ancestor
This is the actual bugfix.
* Pass parent type and props to insert/delete hydration warning hooks
For this to work, we need to split the API into a container and normal
version. Since the root doesn't have a type nor props.
* Ignore SSR warning using explicit suppressHydrationWarning option
This lets you ignore the warning on a single element and its direct child
content. This is useful for simple fields that you're expecting to fail
such as time stamps.
Note that this still won't patch up such content so it'll remain
inconsistent. It's also not suitable for nested complex content that may
change.
* Suppress warning of inserted/deleted direct children
* Add fixture testing hydration warning
Also fixing the render->hydrate API change in the fixture
* Add hooks when text hydration doesn't match up
The purpose of these hooks is to pass the parent context to them. I don't
want to do that in the normal hydrateTextInstance hooks since this is
only used in DEV. This is also in line with what happens if there is no
text instance at all and we invoke didNotFindHydratableTextInstance.
* Move mismatch text hydration warning to the new hooks
This lets us ignore this call when we have parent props available and
the suppression flag is set.
* Inject the right event emitter
Previously this was injecting the ReactNativeEventEmitter even though
we want the ReactNativeRTEventEmitter.
RCTEventEmitter is also just an abstraction around BatchedBridge that
registers a single name. We can't register more than one with it. Removed
that abstraction for now so we don't have to add it back into the RN repo.
* Unify appendChildToDetachedParent and appendChild, separate root
Merge appendChildToDetachedParent and appendChild. We don't need the distinction.
We do however need a separate notion for the root container.
Calling this `appendChildToContext` since Context has a meaning here.
* Add a simple shallow comparison so that we don't send updates for equal props
This still sends all props if any differs. Not sure we'll want that but I
think so.
* Add BatchedBridge to bundle externals
* Lint
* Added check to deduplicate function type warning calls on each component type
* Added test to check that 'function type as React child' warning is deduplicated correctly by component type
* Ran prettier on added code
* Modified test checking deduplication of 'Functions are not valid as a React child' warning so it will check against rerendering component now
* Deleted docs folder
* Deleted www folder
* Remove Netlify website build command
* Removed refs to docs and www from ESlint config
* Removed refs to www/docs from Flow config
* Removed unnecessary .gitignore config
* Updated license check to remove refs to docs
* Removed gh-pages specific portions of Circle build scripts
There may be more that we can remove (eg set_up_github_keys.sh) but I'm not positive
* Removed docs specific license
When testing range input change events, clicking the knob would cause
it to move if the click region wasn't precisely on the center of the
knob.
This is annoying! This commit adds a button to focus the range input
knob and takes a small pass at styling buttons.
A label would work here too, however it does not generate a focus ring
in all browsers.
* Rename rootNodeID -> tag
* Process RT props before forwarding them along
This is needed because the children prop can't be serialized.
Also, some minor placeholder for events.
* Add regression test for CR-insensitive hydration
* Normalize CR when comparing server HTML to DOM
* Move tests in the file
* Add a failing test for comparing attributes
* Normalize CR for attributes too
* Add a test case for CR in dangerouslySetInnerHTML
* Undo the fix per feedback
* Change the fix to be DEV-only and still patch up LF -> CR
* Remove the dangerouslySetInnerHTML test
It's always going to "pass" because we normalize HTML anyway.
Except that it won't pass because we intentionally don't patch up dangerouslyInnerHTML.
* Fix issue that Flow failed to catch
* Add null character tests
* Normalize both client and server value for the warning
* Fix the bug
* Normalize replacement character away as well
* Fix outdated comment
* Add a failing test for text nodes within components
* Reset the text node flag only when emitting tags
This ensures we don't reset it when we exit components that return strings.
* Add a failing test for a more complex tree
* Also reset text flag when emitting a footer
This fixes the {'a'}</div>{'b'} case and prevents an unnecessary comment before 'b'.
We heard from Chrome engineers that creating too many Range objects slows down Chrome because it needs to keep track of all of them for the case that anchor/focus nodes get removed from the document. We can just implement this calculation without ranges anyway.
jsdom doesn't support Range objects, but I copied the fuzz test code into my browser and manually compared it against our old implementation https://gist.github.com/sophiebits/2e6d571f4f10f33b62ea138a6e9c265c; with 200,000 trials no differences were found.
This is an experimental new protocol for some experiments we want to play
with. To make that easier, I'm just going to fork it.
This experiment won't use the event system so I by-pass it and just invoke
functions on the props object for now.
I also fork the UIManager into a new RTManager.
* style(docsearch): add cursor + logo
fixes#10965
Not completely convinced about the cursor colour, but I couldn't really find a better one, cc @joecritch
* fix margin
* style(docsearch): add cursor + logo
fixes#10965
Not completely convinced about the cursor colour, but I couldn't really find a better one, cc @joecritch
* padding
* [Website] Add titles and labels to iframes and images on Community pages
**what is the change?:**
- add titles to all iframes
- add alt tags to images
- add `aria-label` to some links which only have images as contents.
**why make this change?:**
Based on warnings thrown by aXe a11y audit of those pages
**test plan:**
Manual testing
**issue:**
None
* remove redundant alt tags
These were broken after 16 was tagged as `latest` on npm. This fixes that problem, and also adds two template options: one for React 16 and one for React 15. I figure we should provide both for now, since there's still a lot of 15.x users.
This documentation change clarifies how the method `tick()` relates to the example given in the State and Lifecycle documentation. Why this change is necessary is because it may be confusing for beginners who may mistake `tick()` to be a lifecycle API hook. To clarify, the verbiage is changed so that it becomes more clear that the method is specific to the component and not the API.
* Use ES6 module instead of commonJS
As far as I know, we're using ES6 modules throughout the docs. For the sake of consistency :)
* Convert all CommonJS requires to ES6 module
removing the old mention of license for examples. since there is no examples in the repository and also the license for them was deleted [here](#10890)
* [Gatsby docs a11y] Add `aria-label` to search input
**what is the change?:**
See title.
**why make this change?:**
There was no label on this input, and screen readers might not have been
able to identify it's purpose.
[The `placeholder` doesn't count as a label.](http://a11yproject.com/posts/placeholder-input-elements/)
**test plan:**
Manually inspected the HTML in the devtools, and ran the aXe a11y audit
tool, and the warning generated by aXe was gone.
**issue:**
Checklist item on list of docs a11y issues -
https://github.com/bvaughn/react/wiki/Gatsby-A11y-Fixes
* [Gatsby Docs a11y] Increase contrast of 'installation' page tabs
**what is the change?:**
Change the dark blue used for the text/background of the tabs on the
'installation' page to a slightly darker blue, which we were already
using for the 'focus' style of the tabs. It looked a bit weird before,
imo, when the 'focus' was darker.
Now the 'focus' style just lightens the border to the new signature
blue.
**why make this change?:**
To add enough contrast that folks who see colors differently can still
decipher the writing on the tabs on this page.
We plan to refactor this page and remove the tabs soon, so not too
worried about making this fix perfect.
**test plan:**
Manual testing - loaded the page and it looks ok, and ran aXe a11y
audit, no more warnings about contrast. :)
(Flarnie will insert a screenshot)
**issue:**
checklist item on https://github.com/bvaughn/react/wiki/Gatsby-A11y-Fixes
* Add a failing test that prints "null" in the warning instead of the stack
* Don't reset the current fiber during reconciliation
It should only be reset when we stop doing work.
Otherwise, any warnings after the reset will lose the component stack.
The reset in getMaskedContext() was completely unnecessary.
It is always called with the same fiber as the current work in progress.
Therefore, I add a DEV-only warning assertion to ensure we don't regress, and remove the reset.
The reset in processChildContext() is necessary because it can be called outside of reconciliation.
Unfortunately, we have to keep this hack in until we can remove unstable_renderSubtreeIntoContainer().
To work around it, I restore the previous fiber instead of resetting.
* Decouple setting the current fiber and phase
These are two distinct actions.
This helps make it clearer when we're actually changing the current pointer.
I'm also removing an overengineered hack I previously added for unstable_renderSubtreeIntoContainer. It's not necessary now that we don't null the pointer all the time.
This makes the code more straightforward.
* Centralize the pointer updates in the scheduler
* Fix for createHTMLDocument API specific to IE11
The createHTMLDocument API title parameter is not optional in IE while other browsers don't care IE11 will throw if an argument is not passed. This only impacts react.dom.development not react.dom.production.
* Tweak
Adds a new docs website, built with Gatsby JS, to replace the old Jekyll site. Source code for the new site lives in /www (although markdown and YML data still comes from the legacy /docs folder).
Changes to either markdown or website source code can be previewed on Netlify. The react-js bot should automatically add comments to each PR with preview links. (This preview is generated by running the newly-added yarn build:docs command in the root package.json.)
The majority of the changes in this PR are contained within the new /www directory. However some minor modifications have been made to existing content in the /docs directory:
* Modified frontmatter author block to always be an array
* Small markdown formatting tweaks
* Remove allowTransparency attribute
`allowtransparency` is an Internet Explorer-only attribute that
controls the background transparency of an iFrame. When set to true,
it respects the background color of the iFrame. When set to false, it
sets the background color to that of the document.
This feature was removed in IE9 - falling out of React's support
commitment.
Developers that have somehow figured out how to get IE8 to work with
React 16.x can still use `allowtransparency="true"`, since React now
supports unrecognized attributes.
* Use correct attribute script location
* Use new UMD bundles in attribute fixtures
* Update attribute snapshot
* Blank for CI
* Add link to React community on Hashnode
React community on Hashnode has more than 10K followers. It'd be nice if we can point developers to this place.
* Consistency in heading + remove the sales pitch-y bit
* Update portals docs "child" language
This commit changes the portals docs so that the language of the Parent
no longer feels like it is missing a word with "is not a child the div
with onClick handler" and replaces that with "is not a direct child of
the div with the onClick handler".
closes#10868
* Update portals.md
* "Write Code in Your Editor": Split step 5 into 2 steps
To me it wasn't clear (enough) that I had to copy the file's content from [here](https://codepen.io/gaearon/pen/oWWQNa?editors=0010) *and* add the three lines to the top.
* Update tutorial.md
* Update Portals Documentation
Correct some grammar to be more explicit and clear. Update example CodePen to better match code found in documentation. Update code example styles to match other code examples (ie. 'State and Lifecycle', 'Handling Events').
* Clean up comment to be accurate to example
There was a small comment overlooked when reviewing the documentation. This fixes it to be accurate to the example as well as grammatically correct.
* Update portals.md
* More fixes
* Add ReactTestRenderer documentations
* Add TestRenderer documentations
* TestRenderer is not experiment
* Add a link for jsdom
* Use ES Modules syntax
* Twaek
* Add a Link component
* Use Jest assertions
* Move a documentation for createNodeMock to Idea section
* Renamed
* Tweak
* Rename
* More explicit
* Add a usecase for createNodeMock
Did find and replace in TextMate.
```
find: (?:( \*)( ))?Copyright (?:\(c\) )?(\d{4})\b.+Facebook[\s\S]+(?:this source tree|the same directory)\.$
replace: $1$2Copyright (c) $3-present, Facebook, Inc.\n$1\n$1$2This source code is licensed under the MIT license found in the\n$1$2LICENSE file in the root directory of this source tree.
```
* First shot at updating changelog for 16.0
**what is the change?:**
Added an 'unreleased' section to the changelog with info from https://github.com/facebook/react/issues/10294
**why make this change?:**
To get things set for the 16.0 release.
**test plan:**
Visual inspection
**issue:**
https://github.com/facebook/react/issues/8854
* Fix typos and formatting errors in changelog
* Add requestAnimationFrame and remove "New helpful warnings"
**what is the change?:**
In response to helpful code review -
- Add mention of dependency on `requestAnimationFrame` and need to
polyfill that as well as `Map` and `Set`
- Remove "New helpful warnings" section; it was incomplete, and there
are so many new and updated warnings that it might not be reasonable
to cover them in the changelog.
**why make this change?:**
Accuracy
**test plan:**
Visual inspection
**issue:**
issue #8854
* Improve wording
* Improve wording and fix missing links
* Add backticks to file names & code; wording tweak
* Break "Major Changes" into "New Feature" and "Breaking Changes"
* Add server side render changes to 16.0 changelog
* Change gist link from mine to gaearons
* Add note about returning fragments
* fix misc nits
* Misc. formatting/wording fixes to changelog
**what is the change?:**
Thanks to the kind code review comments of @gaearon and @nhunzaker we
have
- removed the non-deterministic bold styling on some bullet points
- improved wording of the bullet points for portals, attribute whitelist
changes, and server rendering changes
- Add note about error boundaries including a breaking change to error
handling behavior.
- punctuation and capitalization fixes
**why make this change?:**
Clarity and correctness
**test plan:**
Visual inspection
**issue:**
https://github.com/facebook/react/issues/8854
* fix broken link
Prevents a push/pop mismatch when bailing out on HostRoots. This is
currently unobservable, because HostRoots never bail out on low
priority, but this does happen with prerendering.
I found this when rebasing #10624 on top of master.
* ReactNativeBridgeEventPlugin supports lazily-registered event types
This accompanies changes on the native side to now specify which event types each view manager supports as part of its view config. Ultimately the goal is to lazily initialize view managers on the native side as well.
* Bubbling and direct attributes are optional on view config
This should help ease transition for pre-existing JS-only components.
* Freeze bundle configs before the build
This ensures we don't accidentally mutate it.
* Fix config mutation during the build uncovered by freeze
* Fix FB isomorphic build by marking object-assign as an external
* Bye bye redundant check
The tutorial hints that a change can be made that allows you to go back
in time then click in the board to create a new entry, but the change is
already present in the example code.
This fix removes the hint and re-words the explanation of the change the
example code is making.
After realizing this was the second time I've visited this exact page within a year and second guessing myself that the `textInput` ref isn't actually the `<input />` element. I decided to attempt to make this a little more explicit; you are actually accessing the method on the child class and not the `focus` method on the dom input element. Having them named the same caused some confusion.
* Improve displayName documentation
* displayName docs: higher-order component lowercased to stay consistent with the rest of the docs
* Rephrase displayName reference docs
NOTE: This commit is not exactly what went out as RC2 because I forgot to push. See tag v16.0.0-rc.2 (d06680ea9e) instead. Bumping the version here so we're at the right place though.
* Add license headers on build bundles
* Add the filename IMO to header
* Preserve headers in production bundles
* Use ECMASCRIPT5_STRICT to preserve "use strict"
* Add missing dependencies in `art` fixture, update `yarn.lock`
**what is the change?:**
See title
**why make this change?:**
We want the `art` fixture to be working so that we can test the latest
version of `react-art`.
**test plan:**
Built and inspected the fixture manually
**issue:**
Prepping for 16.0RC release - https://github.com/facebook/react/issues/10623
* ran prettier
* Added invariant check for native dispatching an unsupported event type
This prevents a case of a silent failure when native dispatches an event that JavaScript does not know how to handle.
* Added iOS direct event type 'onSnapshotReady'
This is used for snapshot testing.
* Import react-art/lib/{Circle,Rectangle,Wedge}.art
Copied from react-art@0.15.1 built files.
* Changes to built files to make ART shapes work
Test Plan: Opened the fixture. React logo shows up with its normal dot, now rendered by a `<Circle />`.
**what is the change?:**
Updates to the latest allowed versions for two dependencies.
`yarn upgrade 'fbjs@^0.8.9'`
and
`yarn upgrade 'prop-types@^15.5.8'`
**why make this change?:**
Prepping for the 16.0 RC, we want to have a reproducible build that is
as close as possible to what new users will get when installing React.
**test plan:**
`yarn && yarn build && yarn test`
**issue:**
https://github.com/facebook/react/issues/10623
* Add AgentConf 2018
We are having another edition of the AgentConf in 2018, which has again a strong focus on react, and we'll be skiing again 😎 Last year's PR for reference: https://github.com/facebook/react/pull/8196
* Update conferences.md
* WIP
* WIP Add the rest of the tests for what we expect re: unknown attributes
**what is the change?:**
Adds tests for the following behavior -
- Numbers and booleans should be converted to strings, and not warn
- NaN, Symbols, functions, and objects should be converted to strings,
and *should* warn
Going to add tests for the not-warning behavior in a follow-up.
These tests are not entirely passing - we either need to change what we
expect or change the behavior.
**why make this change?:**
Gets everyone on the same page about expected behavior, and codifies it
in a maintainable way
**test plan:**
`yarn test src/renderers/dom/shared/__tests__/ReactDOMAttribute-test.js`
**issue:**
https://github.com/facebook/react/issues/10399
* WIP Add check that we *don't* warn when handling some unknown attributes
**what is the change?:**
We are testing the behavior of unknown attributes, which has changed
since React 15.
We want to *not* warn for the following cases -
- null
- undefined
- missing
- strings
- numbers
- booleans
**why make this change?:**
We want to verify that warnings don't get fired at the wrong time.
**test plan:**
`yarn test src/renderers/dom/shared/__tests__/ReactDOMAttribute-test.js`
**issue:**
https://github.com/facebook/react/issues/10399
* ran prettier
* Symbols and functions passed to unknown attributes should remove and warn
* Abstract tests a bit to make them easier to read
* Remove Markdown from test names
I don't think we use this convention anywhere.
* Add an assertion for NaN warning message
* Update ReactDOMAttribute test based on attribute fixture
**what is the change?:**
- booleans don't get stringified
- some warnings have changed since we originally wrote this
**why make this change?:**
The attribute behavior is finalized and now we can test it :D
I also found it handy to have a row with a truly unknown attribute, so
added "imaginaryFriend".
**test plan:**
`yarn test src/renderers/dom/shared/__tests__/ReactDOMAttribute-test.js`
and comparing the tests to the attribute table
**issue:**
https://github.com/facebook/react/issues/10399
* remove imaginaryFriend to resolve conflict
* ran prettier
* Default to first non-disabled option for select
Instead of defaulting to the first option for a select element, which could be a disabled option, we find the first non-disabled option available while we looping through the options. If no option matches, set the first non-disabled option as selected.
* Add ReactDOMSelect test for defaulting to non-disabled options
* Add test fixtures to cover disabled selected options
* Fix bad merge
* Adding Crowdin config file to master repo
* Updated to include additional files while ignoring localized community files stored on github
* Additional files ignored
* Included additional files in root docs directory
* ReactNative doesn't query UIManager for native event types
This is a pre-req to unblock Prepack optimiations for ReactNative apps
* Replaced mock ReactNativeEventTypes with mock Platform
* Added Platform.OS to RN host hooks Flow types
* ReactNative supports lazy view registration
Don't react viewConfig from UIManager when a view is registered, but only when it is used for the first time. This will help unblock Prepack optimizations for RN views.
* Added new lazy-creation method for native views
Also exposed the native view config registry to allow invalid/unsupported host components to fall back to RCTView
* Removed ReactNativeViewConfigRegistry from RN __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
After discussion with Spencer Ahrens and Andy Street, it seems the early fallback behavior was mostly for the early days of Ads Manager when Android didn't yet support a lot of the view types. It should be okay now to use an invarient/redbox instead for unsupported views.
* Removed non-lazy createReactNativeComponentClass impl
There are only a handful of components with JavaScript-defined view configs. It's probably worth making them use the new lazy/async interface as well to be more consistent.
* Remove HTMLPropertyConfig entries for non-boolean values
When we originally removed attributes from the whitelist, we assumed a
few attributes were string booleans, but they are not:
Autocomplete ("on", "off")
https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/Attributes.html#autocomplete
Autocapitalize ("none", "sentence", "words", ...)
https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/Attributes.html#autocapitalize
Autocorrect ("on", "off")
https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/Attributes.html#autocorrect
Autosave (string)
https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/Attributes.html#autosave
* Only HAS_BOOLEAN_VALUE attribute flag can assign booleans
* Use a non-boolean attribute in object assignment tests
* Add HAS_STRING_BOOLEAN_VALUE attribute flag
* Fix boolean tests, add boolean warning.
* Reserved props should allow booleans
* Remove outdated comments
* Style tweaks
* Don't treat dashed SVG tags as custom elements
* SVG elements like font-face are not custom attributes
- Adds exceptions to isCustomAttribute for dashed SVG elements
- Use consistent custom element check across all modules
* Move namespace check to isCustomAttribute. Add caveat for stack.
* Remove unused namespace variable assignment
* Fix the DEV-only whitelist
* Don't read property twice
* Ignore and warn about non-string `is` attribute
* Blacklist "aria" and "data" attributes
* Don't pass unknown on* attributes through
* Remove dead code
* Avoid accessing namespace when possible
* Drop .only in ReactDOMComponent-test
* Make isCustomComponent logic more solid
* Do attribute name check earlier
* Fix fbjs import
* Revert unintentional edit
* Re-allow "data" attribute
We intentionally allowed it.
* Use stricter check when attaching events
* Pass SVG boolean attributes with correct casing
* Fix the test
* Undo the SVG dashed-name fix
Per conversation with @sebmarkbage we decided that the fix is too complicated, and it's unfortunate it depends on the DOM element.
It's only relevant for super rare tags that aren't even working consistently across browsers so we'll leave it unfixed for now.
* Prettier
* Fix lint
* Fix flow
* Pass "aria" through but still warn
* Remove special cases for onfocusin, onfocusout
They're covered by event handler code now.
* Add a more specific warning for unknown events
* Pass badly cased React attributes through with warning
We track nested updates to simulate a stack overflow error and prevent
infinite loops. Every time we commit a tree, we increment a counter.
This works if you only have one tree, but if you update many separate
trees, it creates a false negative.
The fix is to reset the counter whenever we switch trees.
* Load ReactDOMServer into attribute table
* Highlight differences between DOM and server renderer
* Use SSR behavior when comparing behavior across renderers
* Use less severe color if SSR differences are only due to warnings
* Ensure result node's tagName matches what's expected
* Throw on unexpected HTMLUnknownElement
* Add ability to "complete" rows and store state in localStorage
* Sort groups based on size
Also: include tagName and containerTagName in info object.
* Tweak sort order
* Update flow-bin to 0.53.1
* Ran flow-upgrade utility
Manually corrected a few over-eager cases where it tried to replace our ReactElement sub-type.
* Replaced a couple of React.Element types with React
* Removed temporary ReactComponent/ReactComponent Flow types
* Prettier
* Replaced React with React based on Dan's PR feedback
Also canonicalize object results (since these SVG properties are objects).
The canonicalized format is what we compare against.
(This will cause unknown objects to show up as unchanged.)
* Add alphabetical and rev-alphabetical sorting
This is just an initial convenient way to jump to the top or bottom of
the list.
Next we will add a sorting which groups rows together if their behavior
pattern is the same.
* Add sorting to group the rows by behavior pattern
**what is the change?:**
Another sorting option - if the content of a row is the same, it takes
those rows and groups them together.
**why make this change?:**
This will help us find groups of attributes that behave similarly.
**test plan:**
manual testing
* rename variable to be more clear
* [WIP] Table of attribute behavior
* getAttribute helper
* add getters for attributes V-Z
* More special cases
* Add getters for more attributes
* Add tagName to attribute config
* Switch default accessor to getProperty instead of getAttribute
* Add containerTagName and tagName config
* Compare result to default value
* Add overrideStringValue config option
* add section for Sebastian and update a couple more attributes
* 'array with string' should use string override, too
* Add additional value types
Strings on, off, true, false
* more attribute updates
* More attributes
* Remove old directory
* add more attribute configs
* More attributes
* just a couple more attribute updates
* More attributes
* Fix the seb parts
* Fix the seb parts
# Conflicts:
# scripts/attribute-behavior/src/App.js
* More attributes
* Prettier
* More attributes
* More attributes
* Fix some bugs in seb's set
* Fix the rest of flarnie's section
* More attributes
* Prettier
* Finish my section (Andrew)
* Compare against UMD build of master
Once we get past MVP stage we can hook this up to the build system so
these files are automatically copied over.
* Fix attributes that don't have compatible properties
Avoid all undefined reads.
* Test multiple input types
Tests different input types and valueAsNumber property. This value is often
NaN. To compare that we also need to switch to Object.is.
* Ignore checked in copies of React 15 bundles in attribute fixture
**what is the change?:**
We checked in bundles of React v15 to run comparisons of attribute
behavior on DOM elements between 15 and 16.
This commit tells prettier and eslint to ignore those files, and fixes a
prettier lint in one other file from that fixture.
**why make this change?:**
To get CI passing.
**test plan:**
`yarn prettier` doesn't change anything, eslint passes
**issue:**
* update README for attribute table fixture
* run prettier again
When the feature flag enableAsyncSubtreeAPI is true,
React.unstable_AsyncComponent creates an async subtree. When it's false,
it behaves like a normal, sync React component. We use this flag in www
as a fail safe so that if we ship an async bug, we can set the flag to
false and revert back to sync mode.
For open source, we should enable the feature flag.
* Add early warning for non-functional event listeners
* Use functional listeners in ReactDOMComponent test
To avoid triggering the non-functional event listener component
* spy on console.error in non-function EventPluginHub test
This should warn from ReactDOMFiberComponent, but we just ignore it here
* Remove redundant check for listener
* Add expectation for non-functional listener warning in EventPluginHub
* Hoist listener typeof check in hot paths
* Include stack addendum in non-functional listener warning
* Make it pretty
* Remove it.onnly from ReactDOMFiber test
* Fix message
* Update expected message
* Change invariant message to match the new style
* Fix remaining warning
This reverts the meaningful (src, non-test) part of commit 3bc64327f0 since we've reverted the commit it depended on in 18083a8a73. I don't fully understand the negative implications of leaving this unreverted but it sounds like consensus is that it's safer to revert.
I left the new fixture and verified it works correctly in Chrome 62 Mac, as well as the jest tests passing.
* Add missing single-word attributes to property warning list
* Alphabetize svg and html configs in possible names
* Add basic test coverage for known single word attributes
* Add note about including whitelist properites in `possibleStandardNames
* Also add attribute sync comment to possibleStandardNames
* add renderer id to react-devtools injection
* rename renderer id to rendererPackageName in react-dom injection
* add rendererPackageName to react-native entries
**what is the change?:**
This reverts 0b220d0f04
Which was part of https://github.com/facebook/react/pull/10238
**why make this change?:**
When trying to sync the latest React with FB's codebase, we had failing
integration tests.
It looks like they are running with an old version of Chrome and there
is something related to file upload that fails when these polyfills are
missing.
For now we'd like to revert this to unblock syncing, but it's worth
revisiting this change to try and add some polyfill for FB and remove it
from React, or to fix whatever the specific issue was with our file
upload error.
**test plan:**
`yarn test` and also built and played with the `dom` and `packaging`
fixtures
* Add invariant check for composite components to event simulation test utils
* Change simulate variable names from domComponentOrNode to domNode, language for new simulate invariant, and add space in existing invariant
* Update test name
* Update test for invariant with shallow rendering
* Update text for existing invariant and change comments to reflect change to only domNode usage
* Update text for existing invariant to reflect syntax with new invariant
* Update ReactTestUtilsEntry.js
* Update React element invariant to reflect usage with shallow rendering
* Move Simulate-related tests into Simulate block
* Run prettier
* Add babel transform for object getters
**what is the change?:**
We were not transforming object getters[1], and our new TestRenderer
uses one.[2]
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
[2]: https://github.com/facebook/react/blob/master/src/renderers/testing/ReactTestRendererFiberEntry.js#L569
**why make this change?:**
Our internal build system was not supporting object getters.
**test plan:**
`yarn build && yarn test`
Also built and opened the 'packaging' fixture.
Honestly I'm not sure what else to test, this seems pretty low risk.
**issue:**
None opened yet
* Replace object getter with `Object.defineProperty` in TestRenderer
**what is the change?:**
Replaces an Object Getter [1] with `Object.defineProperty`.
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
**why make this change?:**
Our internal build system does not support object getters.
**test plan:**
We should do follow-up work to ensure that this doesn't come up again -
we can't commit code which uses object getters.
**issue:**
No issue opened yet
* Tweak the Object.defineProperty call in test renderer to make flow pass
**what is the change?:**
- switched from `Object.defineProperties` to `Object.defineProperty`
- set some undefined properties to get flow to pass
**why make this change?:**
- Flow doesn't seem to play nicely with `Object.defineProperty/ies`
calls, specifically when you implement `get` and `set` methods.
See https://github.com/facebook/flow/issues/1336
- Switched from `properties` to `property` because it seems more
conventional in our codebase to use `property`, and I'm only setting
one anyway.
**test plan:**
`flow`
**issue:**
no issue
* More flow type tweaking
**what is the change?:**
Forced the typing of an argument to 'Object.defineProperty' to be
'Object' to avoid an issue with Flow.
**why make this change?:**
To get tests passing and flow passing.
**test plan:**
`flow && yarn test`
**issue:**
* Throw error to warn of mistaken loading of prod + dev React bundles
**what is the change?:**
Credit to @gaearon for coming up with a clever way to check for this. :)
I mainly just did the manual testing and fixed a couple of typos in his
idea.
I'd like to do a follow-up PR to add a link and a page explaining this
issue more and suggesting how to fix it.
**why make this change?:**
We want to warn for an unfortunate gotcha for
the following situation -
1. Wanting to shrink their JS bundle, an engineer runs it through
'uglifyjs' or some other minifier. They assume this will also do
dead-code-elimination, but the 'prod' and 'dev' checks are not
envified yet and dev-only code does not get removed.
2. Then they run it through browserify's 'envify' or some other tool to
change all calls to 'process.env.NODE_ENV' to "production". This
makes their code ready to ship, except the 'dev' only dead code is
still in the bundle. Their bundle is twice as large as it needs to
be, due to the dead code.
This was a problem with the old build system before, but with our new
build system output it's possible to detect and throw an informative
error in this case.
**test plan:**
1. run the build in react as usual; `yarn build`
2. manually run 'uglifyjs -mt' on 'build/packages/react/index.js' to
simulate mistakenly minifying React before env variables are
resolved, which skips dead code elimination.
3. run the fixtures build - `cd fixtures/packaging && node
./build-all.js && serve ../..`
4. Visit just the production browserify fixture -
http://localhost:5000/fixtures/packaging/browserify/prod/
5. You should see the error thrown indicating this problem has occurred.
(Flarnie will insert a screenshot)
6. Do the above steps with NO uglifyjs step, and verify that no error is
thrown. When there is no minification applied, we don't assume that
this mix-up has occurred.
(Flarnie will insert a screenshot)
**issue:**
fixes#9589
* Remove extra 'prod' env. check and add link to docs in error message
**what is the change?:**
Based on helpful feedback from @gaearon
- removed outer check that `process.env.NODE_ENV` is "production" since
we are only calling the `testMinification` method inside of another
check for "production" environment.
- Added an fburl that points to [our current docs on using the production version of React](https://facebook.github.io/react/docs/optimizing-performance.html#use-the-production-build)
**why make this change?:**
To save an extra layer of conditionals and to make the error message
more clear.
**test plan:**
Same test plan as earlier -
1. run the build in react as usual; yarn build
2. manually run 'uglifyjs -mt' on 'build/packages/react/index.js' to
simulate mistakenly minifying React before env variables are
resolved, which skips dead code elimination.
3. run the fixtures build - cd fixtures/packaging && node ./build-all.js && serve ../..
4. Visit just the production browserify fixture -
http://localhost:5000/fixtures/packaging/browserify/prod/
You should see the error thrown indicating this problem has occurred.
(Flarnie will insert a screenshot in comments on the PR)
6. Do the above steps with NO uglifyjs step, and verify that no error is thrown. When there is no minification applied, we don't assume that this mix-up has occurred.
(Flarnie will insert a screenshot in the comments on the PR.)
**issue:**
https://github.com/facebook/react/issues/9589
* WIP fix and test 'testMinificationUsedDCE' method
**what is the change?:**
- Instead of looking for one match when having the method inspect it's
own source, we look for two matches, because the search itself will be
a match.
- WIP moving this method into another file and testing it.
Next steps:
- Figure out why the babel.transform call is not actually minifying the
code
- Add tests for uglifyjs
- Update build process so that this file can be accessed from
`packages/react/index.js`
**why make this change?:**
- We had a bug in the 'testMinification' method, and I thought the name
could be more clear. I fixed the code and also changed the name.
- In order to avoid other bugs and keep this code working in the future
we'd like to add a unit test for this method. Using the npm modules
for 'uglifyjs' and 'babel'/'babili' we should be able to actually test
how this method will work when minified with different configurations.
**test plan:**
`yarn test`
**issue:**
https://github.com/facebook/react/issues/9589
* Add babeli and uglifyjs as dev-only dependencies
**what is the change?:**
See commit title
**why make this change?:**
In order to test that we are correctly detecting different minification
situations, we are using these modules in a test.
**test plan:**
NA
**issue:**
https://github.com/facebook/react/issues/9589
* Fix typo and add 'uglifyjs' tests
**what is the change?:**
There was a mix-up in the conditional in 'testMinificationUsedDCE' and
this fixes it.
The great new tests we added caught the typo. :)
Next steps:
- get the tests for 'babili' working
- update build scripts so that this the 'testMinificationUsedDCE'
module is available from 'packages/react/index.js'
**why make this change?:**
We want to modularize 'testMinificationUsedDCE' and test it.
This verifies that the method warns when `uglifyjs` is used to minify
but dead code elimination is not done, in a production environment.
Generally this is a 'gotcha' which we want to warn folks aboug.
**test plan:**
`yarn test src/shared/utils/__tests__/testMinificationUsedDCE-test.js`
**issue:**
https://github.com/facebook/react/issues/9589
* Run prettier
* var -> const/let
* Require specific version of `uglify-js`
**what is the change?:**
Removed the '^' from the npm package requirement
**why make this change?:**
I am seeing failures in CI that show `uglify-js` is returning different
output there from my local environment. To further debug this I'd like
to run CI with the exact same version of `uglify-js` that I am using
locally.
**test plan:**
push and see what CI does
**issue:**
https://github.com/facebook/react/issues/9589
* Add build step copying testMinificationUsedDCE into build/packages/react/cj
**what is the change?:**
This is a first step - we still need (I think) to process this file to
get it's contents wrapped in an 'iffe'.
Added a step to the build script which copies the source file for the
'testMinificationUsedDCE' module into the 'cjs' directory of our react
package build.
**why make this change?:**
We want this module to be available to the 'index.js' module in this
build.
**test plan:**
Will do manual testing once the build stuff is fully set up.
**issue:**
* Inline 'testMinificationUsedDCE' and remove unit test for now
What:
- Inlines the 'testMinificationUsedDCE' method into
'packages/react/index.js'
- Removes unit test for 'testMinififcationUsedDCE'
- Puts dependencies back the way that they were; should remove extra
dependencies that were added for the unit test.
Why:
- It would add complexity to the build process to add another file to
the 'build/packages/react/cjs' folder, and that is the only way to
pull this out and test it. So instead we are inlining this.
* Revert unintentional changes to dependency versions, variable placing
**what is the change?:**
- We had updated and added some dependencies, but ended up reverting
this in a previous commit. The `yarn.lock` and `package.json` needed
updated still though.
- There is a call to `Function.toString` which we wanted to wrap in a
`try/catch` block.
**why make this change?:**
To remove unrelated dependency changes and increase the safety of the
`Function.toString` call.
**test plan:**
Manual testing again
**issue:**
https://github.com/facebook/react/issues/9589
* Allow custom attributes. Add flag to toggle custom attribute behavior
* Update custom attribute logic
- Only allow string attributes
- Remove custom attribute feature flag
- Add additional tests for data, aria, and custom attributes
* Allow numbers and booleans custom attributes. Cut isCustomAttribute
* Cover objects with custom attributes in warning test
* Rename DOMProperty.isWriteable to shouldSetAttribute
* Rework conditions in shouldSetProperty to avoid edge cases
* Update unknown property warning to include custom attribute information
* Remove ref and key from reserved props
* Ensure SSR test coverage for DOMProperty injections
* Add ajaxify attribute for internal FB support
* Ajaxify is a stringifiable object attribute
* Remove non-case sensitive standard attributes. Make ARIA hook dev only.
* Update test name for custom attributes on custom elements
* Remove SSR custom injection test
* Remove case sensitive props
* Remove onAfterResetModules hooks in SSR render tests
* Add back a few attributes and explain why they are needed
* Remove possibleStandardNames from DOMProperty.js
* Fix typo in HTMLPropertyConfig comment
* Remove duplicative comment
* Add back loop boolean property
* Do not allow assignment of attributes that are aliased
* Update custom attribute test to check value, not just presence
* Address case where class is assigned as an attribute on custom elements. Improve SSR tests
* Cover cases where className and for are given to custom elements
* Remove unnecessary spys on console.error. Reduce extra space in tests
* Cover cased custom attributes in SSR tests
* Custom attributes are case sensitive
* Allow uppercase letters in custom attributes. Address associated edge cases
* Allow improperly cased aliased attributes. Add additional tests
* Handle special properties like onFocusOut
* Add some comments to document where casing matters. Remove DOMPropertyNames
* Fix spelling mistake in ajaxify HTML property comment
* Make ARIA enforcement dev-only
* Remove alias test that covers multiple aliases for one property
* Fix typo in comment
* Build SVG aliases dynamically
* Remove unused DOMPropertyNames reference
* Do not translate bad casings of aliased attributes
- classname writes to the DOM as classname
- class does not write to the DOM
- cLASS does not write to the DOM
- arabic-form does not write to the DOM
* Revise the way custom booleans are treated
- Custom attributes can not have boolean values unless they are aria
or data attributes
- Attributes with boolean values have been added back to the whitelist
- Warnings now exclude booleans from supported types
- Associated test coverage
* Add developer warnings for NaN and ARIA hooks
* Use string comparison instead of regex to check for data and aria attributes.
* Warn about unsupported properties without case sensitivity
* Remove attributes that are updated to invalid values
* Support object property values with toString methods. Allow boolean props to coerce objects
* Add back ajaxify test
* Address bad references in ReactDOMComponent-test. Format.
* Revert changes to the docs
We'll update them separately
* Allow all objects and pass incorrect aliases
The prior message was a bit wordy and didn't cover all cases (like the one we discovered while researching #10441).
We can use the new URL to explain background info on the DEV-mode technique we're using in addition to common fixes (eg crossorigin attribute for CDN scripts and Webpack devtools settings). Putting this information behind a link will allow us to more easily edit it in the future as common causes for this issue change.
Resolves#10441
* Add test for nested controlled selects
The failure repros only when two events are fired sequentially, where the second
event is what updates the value.
* Add failure case to DOM select fixture
* Use virtual event target for change event instead of native target
Ensures that we use the same node to make decisions instead of two like
we do now.
This will cause restore to be called or not called consistently.
* Pass native event target to the event
We normally pass the native event target to the event object. This ensures
that we do the same thing here.
We still want to schedule a "restore" on the virtual target though since
those are the only nodes known to React.
* Find callsites that would call toString() if we pass attributes through
* Warn for all object unknown props, not just 'toString' ones
fixing this as per Sebastian's feedback, because we want to find all
objects and not just ones with 'toString' defined. Because there may be
other corner cases and issues that are revealed.
* Wrap warning() calls in a DEV check for RN_* builds too.
* Wrapped several warning() imports and calls in if-DEV checks.
* Removed a useless variable (allTypesByEventName) and loop from ReactNativeBridgeEventPlugin.
* Use GCC instead of Uglify for UMD/NODE bundles
* Prettier run
* Fixes fixtures that were alterated by Pretter and trailing function commas
* prettier on prettier
* updated prettier config
* altered prettier config slightly
* Reverted prettier changes
* updated results.json
* made createFiber create a constructed FiberNode object
* updated comment
* satisfying flow and prettier
* better comments :)
* fixes flow error
* updates comment
* converted function constructor to a ES2015 class
* Revert "converted function constructor to a ES2015 class"
This reverts commit c020982c5fe62446667f6f933c834366c3f009b3.
* fixed some merge conflict issues
* Flow....
* removed exact types to make flow pass
* opted for $FlowFixMe instead
* removed exact types to make flow pass
* opted for $FlowFixMe instead
* run prettier
**Do you want to request a *feature* or report a *bug*?**
**What is the current behavior?**
**If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template: https://jsfiddle.net/84v837e9/).**
**What is the expected behavior?**
**Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?**
**Before submitting a pull request,** please make sure the following is done:
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The three fields below are mandatory.
1. Fork [the repository](https://github.com/facebook/react) and create your branch from `master`.
2. If you've added code that should be tested, add tests!
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes (`npm test`).
5. Format your code with [prettier](https://github.com/prettier/prettier) (`npm run prettier`).
6. Make sure your code lints (`npm run lint`).
7. Run the [Flow](https://flowtype.org/) typechecks (`npm run flow`).
8. If you haven't already, complete the CLA.
Before submitting a pull request, please make sure the following is done:
1. Fork [the repository](https://github.com/facebook/react) and create your branch from `master`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`.
6. If you need a debugger, run `yarn debug-test --watch TestName`, open `chrome://inspect`, and press "Inspect".
7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing: https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
## Test Plan
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes the user interface. -->
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an issue becomes stale
daysUntilStale:90
# Number of days of inactivity before a stale issue is closed
daysUntilClose:7
# Issues with these labels will never be considered stale
exemptLabels:
- "Partner"
- "React Core Team"
- "Resolution: Backlog"
- "Type: Bug"
- "Type: Discussion"
- "Type: Needs Investigation"
- "Type: Regression"
# Label to use when marking an issue as stale
staleLabel:"Resolution: Stale"
issues:
# Comment to post when marking an issue as stale.
markComment:>
This issue has been automatically marked as stale.
**If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open.
We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
# Comment to post when closing a stale issue.
closeComment:>
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!
pulls:
# Comment to post when marking a pull request as stale.
markComment:>
This pull request has been automatically marked as stale.
**If this pull request is still relevant, please leave any comment** (for example, "bump"), and we'll keep it open.
We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated.
# Comment to post when closing a stale pull request.
closeComment:>
Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you!
React is a JavaScript library for building user interfaces.
* **Declarative:** React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug.
* **Component-Based:** Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.
* **Learn Once, Write Anywhere:** We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using [React Native](https://facebook.github.io/react-native/).
* **Learn Once, Write Anywhere:** We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using [React Native](https://reactnative.dev/).
[Learn how to use React in your own project](https://facebook.github.io/react/docs/getting-started.html).
[Learn how to use React in your own project](https://reactjs.org/docs/getting-started.html).
## Installation
React has been designed for gradual adoption from the start, and **you can use as little or as much React as you need**:
* Use [Online Playgrounds](https://reactjs.org/docs/getting-started.html#online-playgrounds) to get a taste of React.
* [Add React to a Website](https://reactjs.org/docs/add-react-to-a-website.html) as a `<script>` tag in one minute.
* [Create a New React App](https://reactjs.org/docs/create-a-new-react-app.html) if you're looking for a powerful JavaScript toolchain.
You can use React as a `<script>` tag from a [CDN](https://reactjs.org/docs/cdn-links.html), or as a `react` package on [npm](https://www.npmjs.com/package/react).
## Documentation
You can find the React documentation [on the website](https://reactjs.org/docs).
Check out the [Getting Started](https://reactjs.org/docs/getting-started.html) page for a quick overview.
The documentation is divided into several sections:
You can improve it by sending pull requests to [this repository](https://github.com/reactjs/reactjs.org).
## Examples
We have several examples [on the website](https://facebook.github.io/react/). Here is the first one to get you started:
We have several examples [on the website](https://reactjs.org/). Here is the first one to get you started:
```jsx
classHelloMessageextendsReact.Component{
render(){
return<div>Hello{this.props.name}</div>;
}
functionHelloMessage({name}){
return<div>Hello{name}</div>;
}
ReactDOM.render(
<HelloMessagename="John"/>,
<HelloMessagename="Taylor"/>,
document.getElementById('container')
);
```
This example will render "Hello John" into a container on the page.
This example will render "Hello Taylor" into a container on the page.
You'll notice that we used an HTML-like syntax; [we call it JSX](https://facebook.github.io/react/docs/introducing-jsx.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. We recommend using [Babel](https://babeljs.io/) with a [React preset](https://babeljs.io/docs/plugins/preset-react/) to convert JSX into native JavaScript for browsers to digest.
## Installation
React is available as the `react` package on [npm](https://www.npmjs.com/). It is also available on a [CDN](https://facebook.github.io/react/docs/installation.html#using-a-cdn).
React is flexible and can be used in a variety of projects. You can create new apps with it, but you can also gradually introduce it into an existing codebase without doing a rewrite.
The recommended way to install React depends on your project. Here you can find short guides for the most common scenarios:
* [Trying Out React](https://facebook.github.io/react/docs/installation.html#trying-out-react)
* [Creating a New Application](https://facebook.github.io/react/docs/installation.html#creating-a-new-application)
* [Adding React to an Existing Application](https://facebook.github.io/react/docs/installation.html#adding-react-to-an-existing-application)
You'll notice that we used an HTML-like syntax; [we call it JSX](https://reactjs.org/docs/introducing-jsx.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. If you're using React as a `<script>` tag, read [this section](https://reactjs.org/docs/add-react-to-a-website.html#optional-try-react-with-jsx) on integrating JSX; otherwise, the [recommended JavaScript toolchains](https://reactjs.org/docs/create-a-new-react-app.html) handle it automatically.
## Contributing
The main purpose of this repository is to continue to evolve React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React.
The main purpose of this repository is to continue evolving React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React.
### [Code of Conduct](https://code.facebook.com/codeofconduct)
### [Code of Conduct](https://code.fb.com/codeofconduct)
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.fb.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
Read our [contributing guide](https://facebook.github.io/react/contributing/how-to-contribute.html) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React.
Read our [contributing guide](https://reactjs.org/contributing/how-to-contribute.html) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React.
### Beginner Friendly Bugs
### Good First Issues
To help you get your feet wet and get you familiar with our contribution process, we have a list of [beginner friendly bugs](https://github.com/facebook/react/labels/Difficulty%3A%20beginner) that contain bugs which are fairly easy to fix. This is a great place to get started.
To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first issues](https://github.com/facebook/react/labels/good%20first%20issue) that contain bugs which have a relatively limited scope. This is a great place to get started.
### License
React is [BSD licensed](./LICENSE). We also provide an additional [patent grant](./PATENTS).
React documentation is [Creative Commons licensed](./LICENSE-docs).
Examples provided in this repository and in the documentation are [separately licensed](./LICENSE-examples).
If you believe you have found a security vulnerability in React, we encourage you to let us know right away. We will investigate all legitimate reports and do our best to quickly fix the problem.
Please refer to the following page for our responsible disclosure policy, reward guidelines, and those things that should not be reported:
## [Read the React Documentation](https://facebook.github.io/react/)
This folder is not the right place to *read* the documentation.
Instead, head over [to the React website](https://facebook.github.io/react/) to read it.
This folder only contains the source code for the website.
## Installation
If you are working on the site, you will want to install and run a local copy of it.
We use [Jekyll](http://jekyllrb.com/) to build the site using ([mostly](http://zpao.com/posts/adding-line-highlights-to-markdown-code-fences/)) Markdown, and we host it by pushing HTML to [GitHub Pages](http://pages.github.com/).
### Dependencies
In order to use Jekyll, you will need to have Ruby installed. macOS comes pre-installed with Ruby, but you may need to update RubyGems (via `gem update --system`).
Otherwise, [RVM](https://rvm.io/) and [rbenv](https://github.com/sstephenson/rbenv) are popular ways to install Ruby.
The version of the Pygment syntax highlighter used by Jekyll requires Python 2.7.x (not 3.x). macOS comes pre-installed with Python 2.7, but you may need to install it on other OSs.
Once you have RubyGems and installed Bundler (via `gem install bundler`), use it to install the dependencies:
```sh
$ cd react/docs
$ bundle install # Might need sudo.
$ npm install
```
### Instructions
The site requires React, so first make sure you've built the project (via [`grunt`](http://gruntjs.com/getting-started)).
Use Jekyll to serve the website locally (by default, at `http://localhost:4000`):
```sh
$ cd react/docs
$ bundle exec rake
$ bundle exec rake fetch_remotes
$ bundle exec jekyll serve -w
$ open http://localhost:4000/react/index.html
```
We use [SASS](http://sass-lang.com/) (with [Bourbon](http://bourbon.io/)) for our CSS, and we use JSX to transform some of our JS.
If you only want to modify the HTML or Markdown, you do not have to do anything because we package pre-compiled copies of the CSS and JS.
If you want to modify the CSS or JS, use [Rake](http://rake.rubyforge.org/) to compile them:
```sh
$ cd react/docs
$ bundle exec rake watch # Automatically compiles as needed.
# bundle exec rake Manually compile CSS and JS.
# bundle exec rake js Manually compile JS, only.
```
## Afterthoughts
### Updating `facebook.github.io/react`
The easiest way to do this is to have a separate clone of this repository, checked out to the `gh-pages` branch. We have a build step that expects this to be in a directory named `react-gh-pages` at the same depth as `react`. Then it's just a matter of running `grunt docs`, which will compile the site and copy it out to this repository. From there, you can check it in.
**Note:** This should only be done for new releases. You should create a tag corresponding to the release tag in the main repository.
We also have a rake task that does the same thing (without creating commits). It expects the directory structure mentioned above.
```sh
$ bundle exec rake release
```
### Removing the Jekyll / Ruby Dependency
In an ideal world, we would not be adding a Ruby dependency on part of our project. We would like to move towards a point where we are using React to render the website.
// Each of these mixins support comma separated lists of values, which allows different transitions for individual properties to be described in a single style rule. Each value in the list corresponds to the value at that same position in the other properties.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.