* 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
Note: if the issue is about documentation or the website, please file it at:
https://github.com/reactjs/reactjs.org/issues/new
-->
**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. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:**
**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. 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/) typechecks (`yarn flow`).
10. If you haven't already, complete the CLA.
Before submitting a pull request, please make sure the following is done:
**Learn more about contributing:** https://reactjs.org/docs/how-to-contribute.html
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!
Changes that have landed in master but are not yet released.
Click to see more.
</summary>
</details>
## 16.13.1 (March 19, 2020)
### React DOM
* Fix bug in legacy mode Suspense where effect clean-up functions are not fired. This only affects users who use Suspense for data fetching in legacy mode, which is not technically supported. ([@acdlite](https://github.com/acdlite) in [#18238](https://github.com/facebook/react/pull/18238))
* Revert warning for cross-component updates that happen inside class render lifecycles (`componentWillReceiveProps`, `shouldComponentUpdate`, and so on). ([@gaearon](https://github.com/gaearon) in [#18330](https://github.com/facebook/react/pull/18330))
## 16.13.0 (February 26, 2020)
### React
* Warn when a string ref is used in a manner that's not amenable to a future codemod ([@lunaruan](https://github.com/lunaruan) in [#17864](https://github.com/facebook/react/pull/17864))
* Deprecate `React.createFactory()` ([@trueadm](https://github.com/trueadm) in [#17878](https://github.com/facebook/react/pull/17878))
### React DOM
* Warn when changes in `style` may cause an unexpected collision ([@sophiebits](https://github.com/sophiebits) in [#14181](https://github.com/facebook/react/pull/14181), [#18002](https://github.com/facebook/react/pull/18002))
* Warn when a function component is updated during another component's render phase ([@acdlite](https://github.com/acdlite) in [#17099](https://github.com/facebook/react/pull/17099))
* Deprecate `unstable_createPortal` ([@trueadm](https://github.com/trueadm) in [#17880](https://github.com/facebook/react/pull/17880))
* Fix `onMouseEnter` being fired on disabled buttons ([@AlfredoGJ](https://github.com/AlfredoGJ) in [#17675](https://github.com/facebook/react/pull/17675))
* Call `shouldComponentUpdate` twice when developing in `StrictMode` ([@bvaughn](https://github.com/bvaughn) in [#17942](https://github.com/facebook/react/pull/17942))
* Add `version` property to ReactDOM ([@ealush](https://github.com/ealush) in [#15780](https://github.com/facebook/react/pull/15780))
* Don't call `toString()` of `dangerouslySetInnerHTML` ([@sebmarkbage](https://github.com/sebmarkbage) in [#17773](https://github.com/facebook/react/pull/17773))
* Show component stacks in more warnings ([@gaearon](https://github.com/gaearon) in [#17922](https://github.com/facebook/react/pull/17922), [#17586](https://github.com/facebook/react/pull/17586))
### Concurrent Mode (Experimental)
* Warn for problematic usages of `ReactDOM.createRoot()` ([@trueadm](https://github.com/trueadm) in [#17937](https://github.com/facebook/react/pull/17937))
* Remove `ReactDOM.createRoot()` callback params and added warnings on usage ([@bvaughn](https://github.com/bvaughn) in [#17916](https://github.com/facebook/react/pull/17916))
* Don't group Idle/Offscreen work with other work ([@sebmarkbage](https://github.com/sebmarkbage) in [#17456](https://github.com/facebook/react/pull/17456))
* Adjust `SuspenseList` CPU bound heuristic ([@sebmarkbage](https://github.com/sebmarkbage) in [#17455](https://github.com/facebook/react/pull/17455))
* Add missing event plugin priorities ([@trueadm](https://github.com/trueadm) in [#17914](https://github.com/facebook/react/pull/17914))
* Fix `isPending` only being true when transitioning from inside an input event ([@acdlite](https://github.com/acdlite) in [#17382](https://github.com/facebook/react/pull/17382))
* Fix `React.memo` components dropping updates when interrupted by a higher priority update ([@acdlite]((https://github.com/acdlite)) in [#18091](https://github.com/facebook/react/pull/18091))
* Don't warn when suspending at the wrong priority ([@gaearon](https://github.com/gaearon) in [#17971](https://github.com/facebook/react/pull/17971))
* Fix a bug with rebasing updates ([@acdlite](https://github.com/acdlite) and [@sebmarkbage](https://github.com/sebmarkbage) in [#17560](https://github.com/facebook/react/pull/17560), [#17510](https://github.com/facebook/react/pull/17510), [#17483](https://github.com/facebook/react/pull/17483), [#17480](https://github.com/facebook/react/pull/17480))
## 16.12.0 (November 14, 2019)
### React DOM
* Fix passive effects (`useEffect`) not being fired in a multi-root app. ([@acdlite](https://github.com/acdlite) in [#17347](https://github.com/facebook/react/pull/17347))
### React Is
* Fix `lazy` and `memo` types considered elements instead of components ([@bvaughn](https://github.com/bvaughn) in [#17278](https://github.com/facebook/react/pull/17278))
## 16.11.0 (October 22, 2019)
### React DOM
* Fix `mouseenter` handlers from firing twice inside nested React containers. [@yuanoook](https://github.com/yuanoook) in [#16928](https://github.com/facebook/react/pull/16928)
* Remove `unstable_createRoot` and `unstable_createSyncRoot` experimental APIs. (These are available in the Experimental channel as `createRoot` and `createSyncRoot`.) ([@acdlite](http://github.com/acdlite) in [#17088](https://github.com/facebook/react/pull/17088))
## 16.10.2 (October 3, 2019)
### React DOM
* Fix regression in react-native-web by restoring order of arguments in event plugin extractors ([@necolas](https://github.com/necolas) in [#16978](https://github.com/facebook/react/pull/16978))
## 16.10.1 (September 28, 2019)
### React DOM
* Fix regression in Next.js apps by allowing Suspense mismatch during hydration to silently proceed ([@sebmarkbage](https://github.com/sebmarkbage) in [#16943](https://github.com/facebook/react/pull/16943))
## 16.10.0 (September 27, 2019)
### React DOM
* Fix edge case where a hook update wasn't being memoized. ([@sebmarkbage](http://github.com/sebmarkbage) in [#16359](https://github.com/facebook/react/pull/16359))
* Fix heuristic for determining when to hydrate, so we don't incorrectly hydrate during an update. ([@sebmarkbage](http://github.com/sebmarkbage) in [#16739](https://github.com/facebook/react/pull/16739))
* Clear additional fiber fields during unmount to save memory. ([@trueadm](http://github.com/trueadm) in [#16807](https://github.com/facebook/react/pull/16807))
* Fix bug with required text fields in Firefox. ([@halvves](http://github.com/halvves) in [#16578](https://github.com/facebook/react/pull/16578))
* Prefer `Object.is` instead of inline polyfill, when available. ([@ku8ar](http://github.com/ku8ar) in [#16212](https://github.com/facebook/react/pull/16212))
* Fix bug when mixing Suspense and error handling. ([@acdlite](http://github.com/acdlite) in [#16801](https://github.com/facebook/react/pull/16801))
### Scheduler (Experimental)
* Improve queue performance by switching its internal data structure to a min binary heap. ([@acdlite](http://github.com/acdlite) in [#16245](https://github.com/facebook/react/pull/16245))
* Use `postMessage` loop with short intervals instead of attempting to align to frame boundaries with `requestAnimationFrame`. ([@acdlite](http://github.com/acdlite) in [#16214](https://github.com/facebook/react/pull/16214))
### useSubscription
* Avoid tearing issue when a mutation happens and the previous update is still in progress. ([@bvaughn](http://github.com/bvaughn) in [#16623](https://github.com/facebook/react/pull/16623))
## 16.9.0 (August 8, 2019)
### React
* Add `<React.Profiler>` API for gathering performance measurements programmatically. ([@bvaughn](https://github.com/bvaughn) in [#15172](https://github.com/facebook/react/pull/15172))
* Remove `unstable_ConcurrentMode` in favor of `unstable_createRoot`. ([@acdlite](https://github.com/acdlite) in [#15532](https://github.com/facebook/react/pull/15532))
### React DOM
* Deprecate old names for the `UNSAFE_*` lifecycle methods. ([@bvaughn](https://github.com/bvaughn) in [#15186](https://github.com/facebook/react/pull/15186) and [@threepointone](https://github.com/threepointone) in [#16103](https://github.com/facebook/react/pull/16103))
* Deprecate `javascript:` URLs as a common attack surface. ([@sebmarkbage](https://github.com/sebmarkbage) in [#15047](https://github.com/facebook/react/pull/15047))
* Deprecate uncommon "module pattern" (factory) components. ([@sebmarkbage](https://github.com/sebmarkbage) in [#15145](https://github.com/facebook/react/pull/15145))
* Add support for the `disablePictureInPicture` attribute on `<video>`. ([@eek](https://github.com/eek) in [#15334](https://github.com/facebook/react/pull/15334))
* Add support for `onLoad` event for `<embed>`. ([@cherniavskii](https://github.com/cherniavskii) in [#15614](https://github.com/facebook/react/pull/15614))
* Add support for editing `useState` state from DevTools. ([@bvaughn](https://github.com/bvaughn) in [#14906](https://github.com/facebook/react/pull/14906))
* Add support for toggling Suspense from DevTools. ([@gaearon](https://github.com/gaearon) in [#15232](https://github.com/facebook/react/pull/15232))
* Warn when `setState` is called from `useEffect`, creating a loop. ([@gaearon](https://github.com/gaearon) in [#15180](https://github.com/facebook/react/pull/15180))
* Fix a memory leak. ([@paulshen](https://github.com/paulshen) in [#16115](https://github.com/facebook/react/pull/16115))
* Fix a crash inside `findDOMNode` for components wrapped in `<Suspense>`. ([@acdlite](https://github.com/acdlite) in [#15312](https://github.com/facebook/react/pull/15312))
* Fix pending effects from being flushed too late. ([@acdlite](https://github.com/acdlite) in [#15650](https://github.com/facebook/react/pull/15650))
* Fix incorrect argument order in a warning message. ([@brickspert](https://github.com/brickspert) in [#15345](https://github.com/facebook/react/pull/15345))
* Fix hiding Suspense fallback nodes when there is an `!important` style. ([@acdlite](https://github.com/acdlite) in [#15861](https://github.com/facebook/react/pull/15861) and [#15882](https://github.com/facebook/react/pull/15882))
* Slightly improve hydration performance. ([@bmeurer](https://github.com/bmeurer) in [#15998](https://github.com/facebook/react/pull/15998))
### React DOM Server
* Fix incorrect output for camelCase custom CSS property names. ([@bedakb](https://github.com/bedakb) in [#16167](https://github.com/facebook/react/pull/16167))
### React Test Utilities and Test Renderer
* Add `act(async () => ...)` for testing asynchronous state updates. ([@threepointone](https://github.com/threepointone) in [#14853](https://github.com/facebook/react/pull/14853))
* Add support for nesting `act` from different renderers. ([@threepointone](https://github.com/threepointone) in [#16039](https://github.com/facebook/react/pull/16039) and [#16042](https://github.com/facebook/react/pull/16042))
* Warn in Strict Mode if effects are scheduled outside an `act()` call. ([@threepointone](https://github.com/threepointone) in [#15763](https://github.com/facebook/react/pull/15763) and [#16041](https://github.com/facebook/react/pull/16041))
* Warn when using `act` from the wrong renderer. ([@threepointone](https://github.com/threepointone) in [#15756](https://github.com/facebook/react/pull/15756))
### ESLint Plugin: React Hooks
* Report Hook calls at the top level as a violation. ([gaearon](https://github.com/gaearon) in [#16455](https://github.com/facebook/react/pull/16455))
## 16.8.6 (March 27, 2019)
### React DOM
* Fix an incorrect bailout in `useReducer()`. ([@acdlite](https://github.com/acdlite) in [#15124](https://github.com/facebook/react/pull/15124))
* Fix iframe warnings in Safari DevTools. ([@renanvalentin](https://github.com/renanvalentin) in [#15099](https://github.com/facebook/react/pull/15099))
* Warn if `contextType` is set to `Context.Consumer` instead of `Context`. ([@aweary](https://github.com/aweary) in [#14831](https://github.com/facebook/react/pull/14831))
* Warn if `contextType` is set to invalid values. ([@gaearon](https://github.com/gaearon) in [#15142](https://github.com/facebook/react/pull/15142))
## 16.8.5 (March 22, 2019)
### React DOM
* Don't set the first option as selected in select tag with `size` attribute. ([@kulek1](https://github.com/kulek1) in [#14242](https://github.com/facebook/react/pull/14242))
* Improve the `useEffect(async () => ...)` warning message. ([@gaearon](https://github.com/gaearon) in [#15118](https://github.com/facebook/react/pull/15118))
* Improve the error message sometimes caused by duplicate React. ([@jaredpalmer](https://github.com/jaredpalmer) in [#15139](https://github.com/facebook/react/pull/15139))
### React DOM Server
* Improve the `useLayoutEffect` warning message when server rendering. ([@gaearon](https://github.com/gaearon) in [#15158](https://github.com/facebook/react/pull/15158))
### React Shallow Renderer
* Fix `setState` in shallow renderer to work with Hooks. ([@gaearon](https://github.com/gaearon) in [#15120](https://github.com/facebook/react/pull/15120))
* Fix shallow renderer to support `React.memo`. ([@aweary](https://github.com/aweary) in [#14816](https://github.com/facebook/react/pull/14816))
* Fix shallow renderer to support Hooks inside `forwardRef`. ([@eps1lon](https://github.com/eps1lon) in [#15100](https://github.com/facebook/react/pull/15100))
## 16.8.4 (March 5, 2019)
### React DOM and other renderers
- Fix a bug where DevTools caused a runtime error when inspecting a component that used a `useContext` hook. ([@bvaughn](https://github.com/bvaughn) in [#14940](https://github.com/facebook/react/pull/14940))
## 16.8.3 (February 21, 2019)
### React DOM
* Fix a bug that caused inputs to behave incorrectly in UMD builds. ([@gaearon](https://github.com/gaearon) in [#14914](https://github.com/facebook/react/pull/14914))
* Fix a bug that caused render phase updates to be discarded. ([@gaearon](https://github.com/gaearon) in [#14852](https://github.com/facebook/react/pull/14852))
### React DOM Server
* Unwind the context stack when a stream is destroyed without completing, to prevent incorrect values during a subsequent render. ([@overlookmotel](https://github.com/overlookmotel) in [#14706](https://github.com/facebook/react/pull/14706/))
### ESLint Plugin for React Hooks
* Add a new recommended `exhaustive-deps` rule. ([@gaearon](https://github.com/gaearon) in [#14636](https://github.com/facebook/react/pull/14636))
## 16.8.2 (February 14, 2019)
@@ -398,7 +563,7 @@ This release was published in a broken state and should be skipped.
* Fix an issue with `this.state` of different components getting mixed up. ([@sophiebits](https://github.com/sophiebits) in [#12323](https://github.com/facebook/react/pull/12323))
* Provide a better message when component type is undefined. ([@HeroProtagonist](https://github.com/HeroProtagonist) in [#11966](https://github.com/facebook/react/pull/11966))
## React Test Renderer
### React Test Renderer
* Fix handling of fragments in `toTree()`. ([@maciej-ka](https://github.com/maciej-ka) in [#12107](https://github.com/facebook/react/pull/12107) and [@gaearon](https://github.com/gaearon) in [#12154](https://github.com/facebook/react/pull/12154))
* Shallow renderer should assign state to `null` for components that don't set it. ([@jwbay](https://github.com/jwbay) in [#11965](https://github.com/facebook/react/pull/11965))
@@ -617,7 +782,7 @@ Starting with 16.1.0, we will no longer be publishing new releases on Bower. You
* Fix bug in QtWebKit when wrapping synthetic events in proxies. ([@walrusfruitcake](https://github.com/walrusfruitcake) in [#10115](https://github.com/facebook/react/pull/10011))
* Prevent event handlers from receiving extra argument in development. ([@aweary](https://github.com/aweary) in [#10115](https://github.com/facebook/react/pull/8363))
* Fix cases where `onChange` would not fire with `defaultChecked` on radio inputs. ([@jquense](https://github.com/jquense) in [#10156](https://github.com/facebook/react/pull/10156))
* Add support for `controlList` attribute to DOM property whitelist ([@nhunzaker](https://github.com/nhunzaker) in [#9940](https://github.com/facebook/react/pull/9940))
* Add support for `controlList` attribute to allowed DOM properties ([@nhunzaker](https://github.com/nhunzaker) in [#9940](https://github.com/facebook/react/pull/9940))
* Fix a bug where creating an element with a ref in a constructor did not throw an error in development. ([@iansu](https://github.com/iansu) in [#10025](https://github.com/facebook/react/pull/10025))
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.
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <opensource-conduct@fb.com>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
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://reactjs.org/docs/getting-started.html).
@@ -16,7 +16,7 @@ React has been designed for gradual adoption from the start, and **you can use a
* [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/).
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).
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:
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.