* Decouple update queue from Fiber type
The update queue is in need of a refactor. Recent bugfixes (#12528) have
exposed some flaws in how it's modeled. Upcoming features like Suspense
and [redacted] also rely on the update queue in ways that weren't
anticipated in the original design.
Major changes:
- Instead of boolean flags for `isReplace` and `isForceUpdate`, updates
have a `tag` field (like Fiber). This lowers the cost for adding new
types of updates.
- Render phase updates are special cased. Updates scheduled during
the render phase are dropped if the work-in-progress does not commit.
This is used for `getDerivedStateFrom{Props,Catch}`.
- `callbackList` has been replaced with a generic effect list. Aside
from callbacks, this is also used for `componentDidCatch`.
* Remove first class UpdateQueue types and use closures instead
I tried to avoid this at first, since we avoid it everywhere else in the Fiber
codebase, but since updates are not in a hot path, the trade off with file size
seems worth it.
* Store captured errors on a separate part of the update queue
This way they can be reused independently of updates like
getDerivedStateFromProps. This will be important for resuming.
* Revert back to storing hasForceUpdate on the update queue
Instead of using the effect tag. Ideally, this would be part of the
return type of processUpdateQueue.
* Rename UpdateQueue effect type back to Callback
I don't love this name either, but it's less confusing than UpdateQueue
I suppose. Conceptually, this is usually a callback: setState callbacks,
componentDidCatch. The only case that feels a bit weird is Timeouts,
which use this effect to attach a promise listener. I guess that kinda
fits, too.
* Call getDerivedStateFromProps every render, even if props did not change
Rather than enqueue a new setState updater for every props change, we
can skip the update queue entirely and merge the result into state at
the end. This makes more sense, since "receiving props" is not an event
that should be observed. It's still a bit weird, since eventually we do
persist the derived state (in other words, it accumulates).
* Store captured effects on separate list from "own" effects (callbacks)
For resuming, we need the ability to discard the "own" effects while
reusing the captured effects.
* Optimize for class components
Change `process` and `callback` to match the expected payload types
for class components. I had intended for the update queue to be reusable
for both class components and a future React API, but we'll likely have
to fork anyway.
* Only double-invoke render phase lifecycles functions in DEV
* Use global state to track currently processing queue in DEV
This is the first step - pulling the ReactDOMFrameScheduling module out
into a separate package.
Co-authored-by: Brandon Dail <aweary@users.noreply.github.com>
* Added new "native-fb" and "native-fabric-fb" bundles.
* Split RN_DEV and RN_PROD bundle types into RN_OSS_DEV, RN_OSS_PROD, RN_FB_DEV, and RN_FB_PROD. (This is a bit redundant but it seemed the least intrusive way of supporting a forked feature flags file for these bundles.)
* Renamed FB_DEV and FB_PROD bundle types to be more explicitly for www (FB_WWW_DEV and FB_WWW_PROD)
* Removed Haste @providesModule headers from the RB-specific RN renderer bundles to avoid a duplicate name conflicts.
* Remove dynamic values from OSS RN feature flags. (Leave them in FB RN feature flags.)
* Updated the sync script(s) to account for new renderer type.
* Move ReactFeatureFlags.js shim to FB bundle only (since OSS bundle no longer needs dynamic values).
* Added new debug performance tests for AsyncMode, StrictMode, forwardRef, and context provider/consumer components.
* Updated performance labels to exclude AsyncMode and StrictMode.
* Added labels for forwardRef (and inner function) that mirror DevTools labels.
* Add React.isValidElementType()
Per the conversation on #12453, there are a number of third-party
libraries (particularly those that generate higher-order components)
that are performing suboptimal validation of element types.
This commit exposes a function that can perform the desired check
without depending upon React internals.
* Move isValidElementType to shared/
These are based on the ReactNoop renderer, which we use to test React
itself. This gives library authors (Relay, Apollo, Redux, et al.) a way
to test their components for async compatibility.
- Pass `unstable_isAsync` to `TestRenderer.create` to create an async
renderer instance. This causes updates to be lazily flushed.
- `renderer.unstable_yield` tells React to yield execution after the
currently rendering component.
- `renderer.unstable_flushAll` flushes all pending async work, and
returns an array of yielded values.
- `renderer.unstable_flushThrough` receives an array of expected values,
begins rendering, and stops once those values have been yielded. It
returns the array of values that are actually yielded. The user should
assert that they are equal.
Although we've used this pattern successfully in our own tests, I'm not
sure if these are the final APIs we'll make public.
* Implemented new getSnapshotBeforeUpdate lifecycle
* Store snapshot value from Fiber to instance (__reactInternalSnapshotBeforeUpdate)
* Use commitAllHostEffects() traversal for getSnapshotBeforeUpdate()
* Added DEV warnings and tests for new lifecycle
* Don't invoke legacy lifecycles if getSnapshotBeforeUpdate() is defined. DEV warn about this.
* Converted did-warn objects to Sets in ReactFiberClassComponent
* Replaced redundant new lifecycle checks in a few methods
* Check for polyfill suppress flag on cWU as well before warning
* Added Snapshot bit to HostEffectMask
We'll use this in www to test whether the polyfill is better at
scheduling high-pri async work than the native one. My preliminary tests
suggest "yes" but it's hard to say for certain, given how difficult it
is to consistently reproduce the starvation issues we've been seeing.
* Add stack unwinding phase for handling errors
A rewrite of error handling, with semantics that more closely match
stack unwinding.
Errors that are thrown during the render phase unwind to the nearest
error boundary, like before. But rather than synchronously unmount the
children before retrying, we restart the failed subtree within the same
render phase. The failed children are still unmounted (as if all their
keys changed) but without an extra commit.
Commit phase errors are different. They work by scheduling an error on
the update queue of the error boundary. When we enter the render phase,
the error is popped off the queue. The rest of the algorithm is
the same.
This approach is designed to work for throwing non-errors, too, though
that feature is not implemented yet.
* Add experimental getDerivedStateFromCatch lifecycle
Fires during the render phase, so you can recover from an error within the same
pass. This aligns error boundaries more closely with try-catch semantics.
Let's keep this behind a feature flag until a future release. For now, the
recommendation is to keep using componentDidCatch. Eventually, the advice will
be to use getDerivedStateFromCatch for handling errors and componentDidCatch
only for logging.
* Reconcile twice to remount failed children, instead of using a boolean
* Handle effect immediately after its thrown
This way we don't have to store the thrown values on the effect list.
* ReactFiberIncompleteWork -> ReactFiberUnwindWork
* Remove startTime
* Remove TypeOfException
We don't need it yet. We'll reconsider once we add another exception type.
* Move replay to outer catch block
This moves it out of the hot path.
* Switch to JSX API for context
80% sure this will be the final API. Merging this now so we can get this
into the next www sync in preparation for 16.3.
* Promote context to a stable API
* Replace unstable_AsyncComponent with Unstable_AsyncMode
Mirrors the StrictMode API and uses the new Mode type of work.
* internalContextTag -> mode
Change this now that we have a better name
* Unstable_ -> unstable_
A new feature flag has been added, debugRenderPhaseSideEffectsForStrictMode. When enabled, StrictMode subtrees will also double-invoke lifecycles in the same way as debugRenderPhaseSideEffects.
By default, this flag is enabled for __DEV__ only. Internally we can toggle it with a GK.
This breaks several of our incremental tests which make use of the noop-renderer. Updating the tests to account for the double-rendering in development mode makes them significantly more complicated. The most straight forward fix for this will be to convert them to be run as internal tests only. I believe this is reasonable since we are the only people making use of the noop renderer.
* New context API
Introduces a declarative context API that propagates updates even when
shouldComponentUpdate returns false.
* Fuzz tester for context
* Use ReactElement for provider and consumer children
* Unify more branches in createFiberFromElement
* Compare context values using Object.is
Same semantics as PureComponent/shallowEqual.
* Add support for Provider and Consumer to server-side renderer
* Store providers on global stack
Rather than using a linked list stored on the context type. The global
stack can be reset in case of an interruption or error, whereas with the
linked list implementation, you'd need to keep track of every
context type.
* Put new context API behind a feature flag
We'll enable this in www only for now.
* Store nearest provider on context object
* Handle reentrancy in server renderer
Context stack should be per server renderer instance.
* Bailout of consumer updates using bitmask
The context type defines an optional function that compares two context
values, returning a bitfield. A consumer may specify the bits it needs
for rendering. If a provider's context changes, and the consumer's bits
do not intersect with the changed bits, we can skip the consumer.
This is similar to how selectors are used in Redux but fast enough to do
while scanning the tree. The only user code involved is the function
that computes the changed bits. But that's only called once per provider
update, not for every consumer.
* Store current value and changed bits on context object
There are fewer providers than consumers, so better to do this work
at the provider.
* Use maximum of 31 bits for bitmask
This is the largest integer size in V8 on 32-bit systems. Warn in
development if too large a number is used.
* ProviderComponent -> ContextProvider, ConsumerComponent -> ContextConsumer
* Inline Object.is
* Warn if multiple renderers concurrently render the same context provider
Let's see if we can get away with not supporting this for now. If it
turns out that it's needed, we can fall back to backtracking the
fiber return path.
* Nits that came up during review
Added new StrictMode component for enabling async warnings (without enabling async rendering). This component can be used in the future to help with other warnings (eg compilation, Fabric).
* Added unsafe_* lifecycles and deprecation warnings
If the old lifecycle hooks (componentWillMount, componentWillUpdate, componentWillReceiveProps) are detected, these methods will be called and a deprecation warning will be logged. (In other words, we do not check for both the presence of the old and new lifecycles.) This commit is expected to fail tests.
* Ran lifecycle hook codemod over project
This should handle the bulk of the updates. I will manually update TypeScript and CoffeeScript tests with another commit.
The actual command run with this commit was: jscodeshift --parser=flow -t ../react-codemod/transforms/rename-unsafe-lifecycles.js ./packages/**/src/**/*.js
* Manually migrated CoffeeScript and TypeScript tests
* Added inline note to createReactClassIntegration-test
Explaining why lifecycles hooks have not been renamed in this test.
* Udated NativeMethodsMixin with new lifecycle hooks
* Added static getDerivedStateFromProps to ReactPartialRenderer
Also added a new set of tests focused on server side lifecycle hooks.
* Added getDerivedStateFromProps to shallow renderer
Also added warnings for several cases involving getDerivedStateFromProps() as well as the deprecated lifecycles.
Also added tests for the above.
* Dedupe and DEV-only deprecation warning in server renderer
* Renamed unsafe_* prefix to UNSAFE_* to be more noticeable
* Added getDerivedStateFromProps to ReactFiberClassComponent
Also updated class component and lifecyle tests to cover the added functionality.
* Warn about UNSAFE_componentWillRecieveProps misspelling
* Added tests to createReactClassIntegration for new lifecycles
* Added warning for stateless functional components with gDSFP
* Added createReactClass test for static gDSFP
* Moved lifecycle deprecation warnings behind (disabled) feature flag
Updated tests accordingly, by temporarily splitting tests that were specific to this feature-flag into their own, internal tests. This was the only way I knew of to interact with the feature flag without breaking our build/dist tests.
* Tidying up
* Tweaked warning message wording slightly
Replaced 'You may may have returned undefined.' with 'You may have returned undefined.'
* Replaced truthy partialState checks with != null
* Call getDerivedStateFromProps via .call(null) to prevent type access
* Move shallow-renderer didWarn* maps off the instance
* Only call getDerivedStateFromProps if props instance has changed
* Avoid creating new state object if not necessary
* Inject state as a param to callGetDerivedStateFromProps
This value will be either workInProgress.memoizedState (for updates) or instance.state (for initialization).
* Explicitly warn about uninitialized state before calling getDerivedStateFromProps.
And added some new tests for this change.
Also:
* Improved a couple of falsy null/undefined checks to more explicitly check for null or undefined.
* Made some small tweaks to ReactFiberClassComponent WRT when and how it reads instance.state and sets to null.
* Improved wording for deprecation lifecycle warnings
* Fix state-regression for module-pattern components
Also add support for new static getDerivedStateFromProps method
Removes the `useSyncScheduling` option from the HostConfig, since it's
no longer needed. Instead of globally flipping between sync and async,
our strategy will be to opt-in specific trees and subtrees.
* Migrated several additional tests to use new .toWarnDev() matcher
* Migrated ReactDOMComponent-test to use .toWarnDev() matcher
Note this test previous had some hacky logic to verify errors were reported against unique line numbers. Since the new matcher doesn't suppor this, I replaced this check with an equivalent (I think) comparison of unique DOM elements (eg div -> span)
* Updated several additional tests to use the new .toWarnDev() matcher
* Updated many more tests to use .toWarnDev()
* Updated several additional tests to use .toWarnDev() matcher
* Updated ReactElementValidator to distinguish between Array and Object in its warning. Also updated its test to use .toWarnDev() matcher.
* Updated a couple of additional tests
* Removed unused normalizeCodeLocInfo() methods
* Call and Return components should use ReactElement
ReactChildFiber contains lots of branches that do the same thing for
different child types. We can unify them by having more child types be
ReactElements. This requires that the `type` and `key` fields are
sufficient to determine the identity of the child.
The main benefit is decreased file size, especially as we add more
component types, like context providers and consumers.
This updates Call and Return components to use ReactElement. Portals are
left alone for now because their identity includes the host instance.
* Move server render invariant for call and return types
* Sort ReactElement type checks by most likely
* Performance timeline should skip over call components
Don't think these were intentionally omitted from the blacklist of
component types.
I went ahead and updated getComponentName to include special types, even
though I don't think they're used anywhere right now.
* Remove surrounding brackets from internal display names
* Use `this` inside invokeGuardedCallback
It's slightly odd but that's exactly how our www fork works.
Might as well do it in the open source version to make it clear we rely on context here.
* Move invokeGuardedCallback into a separate file
This lets us introduce forks for it.
* Add a www fork for invokeGuardedCallback
* Fix Flow
* WIP:use public API
* ReactPortal shifted to shared:all passed
* wrote createPortal method for ReactNoop.(#11299)
* imported ReactNodeList type into ReactNoop.(#11299)
* createPortal method implemented.(#11299)
* exec yarn prettier-all.(#11299)
* Unify the way we fork modules
* Replace rollup-plugin-alias with our own plugin
This does exactly what we need and doesn't suffer from https://github.com/rollup/rollup-plugin-alias/issues/34.
* Move the new plugin to its own file
* Rename variable for consistency
I settled on calling them "forks" since we already have a different concept of "shims".
* Move fork config into its own file
* Warn if `document` is missing by the time invokeGuardedCallback runs in DEV
* Typo
* Add a comment
* Use invariant() instead
* Create event immediately for clarity
* Move ReactFiberTreeReflection to react-reconciler/reflection #11659
* Use * for react-reconciler
We don't know the latest local version, and release script currently doesn't bump deps automatically.
* Remove unused field
* Use CommonJS in entry point for consistency
* Undo the CommonJS change
I didn't realize it would break the build.
* Record sizes
* Remove reconciler fixtures
They're unnecessary now that we run real tests on reconciler bundles.