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.
* 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
* 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
* 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
* 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
* 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
* 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
I don't think "array or iterator" is adding anything, and it may well be confusing, especially since this is one of the first and most common warnings that devs see.
* Simplify imports in ReactChildFiber
* Import type first in ReactCurrentFiber
* Simplify imports in ReactFiberBeginWork
* Simplify imports in ReactFiberScheduler
* Simplify import in ReactFiberTreeReflection
* Simplify import in ReactFiberUnwindWork
* Remove repeated import
* Fix imports from ReactFiberExpirationTime
* Master imports in ReactFiberBeginWork
* Introduce elementType field
This will be used to store the wrapped type of an element. E.g. pure and
lazy.
The existing type field will be used for the unwrapped type within them.
* Store the unwrapped type on the type field of lazy components
* Use the raw tags for lazy components
Instead, we check if the elementType and type are equal to test if
we need to resolve props. This is slightly slower in the normal case
but will yield less code and branching.
* Clean up lazy branches
* Collapse work tag numbering
* Split IndeterminateComponent out from Lazy
This way we don't have to check the type in a hacky way in the
indeterminate path. Also, lets us deal with lazy that resolves to
indeterminate and such.
* Missing clean up in rebase
* Accept promise as element type
On the initial render, the element will suspend as if a promise were
thrown from inside the body of the unresolved component. Siblings should
continue rendering and if the parent is a Placeholder, the promise
should be captured by that Placeholder.
When the promise resolves, rendering resumes. If the resolved value
has a `default` property, it is assumed to be the default export of
an ES module, and we use that as the component type. If it does not have
a `default` property, we use the resolved value itself.
The resolved value is stored as an expando on the promise/thenable.
* Use special types of work for lazy components
Because reconciliation is a hot path, this adds ClassComponentLazy,
FunctionalComponentLazy, and ForwardRefLazy as special types of work.
The other types are not supported, but wouldn't be placed into a
separate module regardless.
* Resolve defaultProps for lazy types
* Remove some calls to isContextProvider
isContextProvider checks the fiber tag, but it's typically called after
we've already refined the type of work. We should get rid of it. I
removed some of them in the previous commit, and deleted a few more
in this one. I left a few behind because the remaining ones would
require additional refactoring that feels outside the scope of this PR.
* Remove getLazyComponentTypeIfResolved
* Return baseProps instead of null
The caller compares the result to baseProps to see if anything changed.
* Avoid redundant checks by inlining getFiberTagFromObjectType
* Move tag resolution to ReactFiber module
* Pass next props to update* functions
We should do this with all types of work in the future.
* Refine component type before pushing/popping context
Removes unnecessary checks.
* Replace all occurrences of _reactResult with helper
* Move shared thenable logic to `shared` package
* Check type of wrapper object before resolving to `default` export
* Return resolved tag instead of reassigning
* Use %s in the console calls
* Add shared/warningWithStack
* Convert some warning callsites to warningWithStack
* Use warningInStack in shared utilities and remove unnecessary checks
* Replace more warning() calls with warningWithStack()
* Fixes after rebase + use warningWithStack in react
* Make warning have stack by default; warningWithoutStack opts out
* Forbid builds that may not use internals
* Revert newly added stacks
I changed my mind and want to keep this PR without functional changes. So we won't "fix" any warnings that are already missing stacks. We'll do it in follow-ups instead.
* Fix silly find/replace mistake
* Reorder imports
* Add protection against warning argument count mismatches
* Address review
* Fix getComponentName() for types with nested $$typeof
* Temporarily remove Profiler ID from messages
* Change getComponentName() signature to take just type
It doesn't actually need the whole Fiber.
* Remove getComponentName() forks in isomorphic and SSR
* Remove unnecessary .type access where we already have a type
* Remove unused type
* Refactor ReactDebugCurrentFiber to use named exports
This makes the difference between it and ReactFiberCurrentFrame a bit clearer.
ReactDebugCurrentFiber is Fiber's own implementation.
ReactFiberCurrentFrame is the thing that holds a reference to the current implementation and delegates to it.
* Unify ReactFiberComponentTreeHook and ReactDebugCurrentFiber
Conceptually they're very related.
ReactFiberComponentTreeHook contains implementation details of reading Fiber's stack (both in DEV and PROD).
ReactDebugCurrentFiber contained a reference to the current fiber, and used the above utility.
It was confusing when to use which one. Colocating them makes it clearer what you could do with each method.
In the future, the plan is to stop using these methods explicitly in most places, and instead delegate to a warning system that includes stacks automatically. This change makes future refactorings simpler by colocating related logic.
* Rename methods to better reflect their meanings
Clarify which are DEV or PROD-only.
Clarify which can return null.
I believe the "work in progress only" was a mistake. I introduced it because I wasn't sure what guarantees we have around .return. But we know for sure that following a .return chain gives us an accurate stack even if we get into WIP trees because we don't have reparenting. So it's fine to relax that naming.
* Rename ReactDebugCurrentFiber -> ReactCurrentFiber
It's not completely DEV-only anymore.
Individual methods already specify whether they work in DEV or PROD in their names.
* Inline fbjs/lib/emptyObject
* Explicit naming
* Compare to undefined
* Another approach for detecting whether we can mutate
Each renderer would have its own local LegacyRefsObject function.
While in general we don't want `instanceof`, here it lets us do a simple check: did *we* create the refs object?
Then we can mutate it.
If the check didn't pass, either we're attaching ref for the first time (so we know to use the constructor),
or (unlikely) we're attaching a ref to a component owned by another renderer. In this case, to avoid "losing"
refs, we assign them onto the new object. Even in that case it shouldn't "hop" between renderers anymore.
* Clearer naming
* Add test case for strings refs across renderers
* Use a shared empty object for refs by reading it from React
* Remove string refs from ReactART test
It's not currently possible to resetModules() between several renderers
without also resetting the `React` module. However, that leads to losing
the referential identity of the empty ref object, and thus subsequent
checks in the renderers for whether it is pooled fail (and cause assignments
to a frozen object).
This has always been the case, but we used to work around it by shimming
fbjs/lib/emptyObject in tests and preserving its referential identity.
This won't work anymore because we've inlined it. And preserving referential
identity of React itself wouldn't be great because it could be confusing during
testing (although we might want to revisit this in the future by moving its
stateful parts into a separate package).
For now, I'm removing string ref usage from this test because only this is
the only place in our tests where we hit this problem, and it's only
related to string refs, and not just ref mechanism in general.
* Simplify the condition
* Don’t error when returning an empty Fragment
When a fragment is reconciled, we directly move onto it’s children.
Since an empty `<React.Fragment/>` will have children of `undefined`,
this would always throw.
To fix this, we bail out in those cases.
* Test the update path as well
* Reuse existing code path
* An even more explicit solution that also fixes Flow
* 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_
* Updated misleading error message in production environment when adding ref to a functional component
* Reverted changes to codes.json
* Updated error message
* 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
* Fix dead code elimination for feature flags
Turning flags into named exports fixes dead code elimination.
This required some restructuring of how we verify that flag types match up. I used the Check<> trick combined with import typeof, as suggested by @calebmer.
For www, we can no longer re-export `require('ReactFeatureFlags')` directly, and instead destructure it. This means flags have to be known at init time. This is already the case so it's not a problem. In fact it may be better since it removes extra property access in tight paths.
For things that we *want* to be dynamic on www (currently, only performance flag) we can export a function to toggle it, and then put it on the secret exports. In fact this is better than just letting everyone mutate the flag at arbitrary times since we can provide, e.g., a ref counting interface to it.
* Record sizes
* Update transforms to handle ES modules
* Update Jest to handle ES modules
* Convert react package to ES modules
* Convert react-art package to ES Modules
* Convert react-call-return package to ES Modules
* Convert react-test-renderer package to ES Modules
* Convert react-cs-renderer package to ES Modules
* Convert react-rt-renderer package to ES Modules
* Convert react-noop-renderer package to ES Modules
* Convert react-dom/server to ES modules
* Convert react-dom/{client,events,test-utils} to ES modules
* Convert react-dom/shared to ES modules
* Convert react-native-renderer to ES modules
* Convert react-reconciler to ES modules
* Convert events to ES modules
* Convert shared to ES modules
* Remove CommonJS support from transforms
* Move ReactDOMFB entry point code into react-dom/src
This is clearer because we can use ES imports in it.
* Fix Rollup shim configuration to work with ESM
* Fix incorrect comment
* Exclude external imports without side effects
* Fix ReactDOM FB build
* Remove TODOs I don’t intend to fix yet
* move to pendingProps to args
* update userFiber in ReactChildFiber
* prettier it
* prettier it
* move expirationTime to the last
* move expirationTime to the last on userFiber
* Move assignment
* Add Fragment as a named export to React
* Remove extra tests for Fragment
* Change React.Fragment export to be a string '#fragment'
* Fix fragment special case to work with 1 child
* Add single child test for fragment export
* Move fragment definition to ReactEntry.js and render components for key warning tests
* Inline createFiberFromElementType into createFiberFromElement
* Update reconciliation to special case fragments
* Use same semantics as implicit childsets for ReactFragment
* Add more fragment state preservation tests
* Export symbol instead of string for fragments
* Fix rebase breakages
* Re-apply prettier at 1.2.2
* Merge branches in updateElement
* Remove unnecessary check
* Re-use createFiberFromFragment for fragment case
* Simplyify branches by adding type field to fragment fiber
* Move branching logic for fragments to broader methods when possible.
* Add more tests for fragments
* Address Dan's feedback
* Move REACT_FRAGMENT_TYPE into __DEV__ block for DCE
* Change hex representation of REACT_FRAGMENT_TYPE to follow convention
* Remove unnecessary branching and isArray checks
* Update test for preserving children state when keys are same
* Fix updateSlot bug and add more tests
* Make fragment tests more robust by using ops pattern
* Update jsx element validator to allow numbers and symbols
* Remove type field from fragment fiber
* Fork reconcileChildFibers instead of recursing
* Use ternary if condition
* Revamp fragment test suite:
- Add more coverage to fragment tests
- Use better names
- Remove useless Fragment component inside tests
- Remove useless tests so that tests are more concise
* Check output of renderer in fragment tests to ensure no silly business despite states being preserved
* Finish implementation of fragment reconciliation with desired behavior
* Add reverse render direction for fragment tests
* Remove unneeded fragment branch in updateElement
* Add more test cases for ReactFragment
* Handle childless fragment in reconciler
* Support fragment flattening in SSR
* Clean up ReactPartialRenderer
* Warn when non-key and children props are passed to fragments
* Add non-null key check back to updateSlot's array's case
* Add test for positional reconciliation in fragments
* Add warning for refs in fragments with stack trace