dillon1000/react

Commit

[Fast Refresh] Remount correctly when an edit changes the component kind (#36950)

Fixes #30659. I'm not confident in this yet but here's what Fable said
based on
https://github.com/react/react/pull/32214#issuecomment-2734436781:

Editing a component from a plain function to a memo or forwardRef
wrapper (or between wrapper kinds) crashed with "Component is not a
function", because canPreserveStateBetween only compared hook
signatures. The edit was classified as state-preserving, so
createWorkInProgress swapped the wrapper object in as the type of a
FunctionComponent fiber and renderWithHooks tried to call it.

Two fixes, both DEV-only:

- canPreserveStateBetween returns false when typeof or $$typeof differ.
A fiber's tag is derived from the kind of its type, so state can never
be preserved across a kind change; these edits must go to staleFamilies
(remount). Nested wrappers need no special handling because register()
creates a family per nesting level ($type/$render ids), and each level's
kind is compared against its own family.

- The reconciler now finds and remounts wrapper fibers whose outer kind
changed. scheduleFibersWithFamiliesRecursively previously resolved
families only through the inner implementation (type/type.render), but a
kind-changing edit is recorded only on the outer type's family, so edits
like memo -> function never reached the scanner and were silently
dropped. The scanner now also checks the elementType's family, and the
_debugNeedsRemount branch in beginWork rebuilds the fiber from
family.current (the latest registered type for the fiber's identity)
rather than the fiber's possibly-stale inner type. This also fixes stale
simple memo remounts recreating as plain functions, dropping the memo
wrapper.

Unlike the reverted #30660 (see #32214), this does not fabricate
families or guess type shapes: families are still created in exactly one
place, and the same ID always resolves to the same family.

Restores the tests from #30660 and adds coverage for changing the inner
type of a memo between function and forwardRef.

Co-authored-by: BIKI DAS <[email protected]>
Co-authored-by: dan <[email protected]>
Browse files
Changed paths4 files
First-parent comparison
M packages/react-reconciler/src/ReactFiberBeginWork.js ModifiedM packages/react-reconciler/src/ReactFiberHotReloading.js ModifiedM packages/react-refresh/src/ReactFreshRuntime.js ModifiedM packages/react-refresh/src/__tests__/ReactFresh-test.js Modified
Patch

Files changed

Rendering syntax-highlighted changes…