Skip to content

Commit 2e3e6a9

Browse files
sebmarkbageeps1lon
andauthored
Unify ReactFiberCurrentOwner and ReactCurrentFiber (#29038)
We previously had two slightly different concepts for "current fiber". There's the "owner" which is set inside of class components in prod if string refs are enabled, and sometimes inside function components in DEV but not other contexts. Then we have the "current fiber" which is only set in DEV for various warnings but is enabled in a bunch of contexts. This unifies them into a single "current fiber". The concept of string refs shouldn't really exist so this should really be a DEV only concept. In the meantime, this sets the current fiber inside class render only in prod, however, in DEV it's now enabled in more contexts which can affect the string refs. That was already the case that a string ref in a Function component was only connecting to the owner in prod. Any string ref associated with any non-class won't work regardless so that's not an issue. The practical change here is that an element with a string ref created inside a life-cycle associated with a class will work in DEV but not in prod. Since we need the current fiber to be available in more contexts in DEV for the debugging purposes. That wouldn't affect any old code since it would have a broken ref anyway. New code shouldn't use string refs anyway. The other implication is that "owner" doesn't necessarily mean "rendering" since we need the "owner" to track other debug information like stacks - in other contexts like useEffect, life cycles, etc. Internally we have a separate `isRendering` flag that actually means we're rendering but even that is a very overloaded concept. So anything that uses "owner" to imply rendering might be wrong with this change. This is a first step to a larger refactor for tracking current rendering information. --------- Co-authored-by: Sebastian Silbermann <[email protected]>
1 parent 4c2e457 commit 2e3e6a9

File tree

13 files changed

+56
-66
lines changed

13 files changed

+56
-66
lines changed

packages/react-devtools-shared/src/__tests__/treeContext-test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,14 +2586,14 @@ describe('TreeListContext', () => {
25862586
utils.act(() => TestRenderer.create(<Contexts />));
25872587

25882588
expect(store).toMatchInlineSnapshot(`
2589-
2, ⚠ 0
2589+
1, ⚠ 0
25902590
[root]
25912591
<ErrorBoundary> ✕
25922592
`);
25932593

25942594
selectNextErrorOrWarning();
25952595
expect(state).toMatchInlineSnapshot(`
2596-
2, ⚠ 0
2596+
1, ⚠ 0
25972597
[root]
25982598
→ <ErrorBoundary> ✕
25992599
`);
@@ -2648,14 +2648,14 @@ describe('TreeListContext', () => {
26482648
utils.act(() => TestRenderer.create(<Contexts />));
26492649

26502650
expect(store).toMatchInlineSnapshot(`
2651-
2, ⚠ 0
2651+
1, ⚠ 0
26522652
[root]
26532653
<ErrorBoundary> ✕
26542654
`);
26552655

26562656
selectNextErrorOrWarning();
26572657
expect(state).toMatchInlineSnapshot(`
2658-
2, ⚠ 0
2658+
1, ⚠ 0
26592659
[root]
26602660
→ <ErrorBoundary> ✕
26612661
`);
@@ -2705,15 +2705,15 @@ describe('TreeListContext', () => {
27052705
utils.act(() => TestRenderer.create(<Contexts />));
27062706

27072707
expect(store).toMatchInlineSnapshot(`
2708-
3, ⚠ 0
2708+
2, ⚠ 0
27092709
[root]
27102710
▾ <ErrorBoundary> ✕
27112711
<Child> ✕
27122712
`);
27132713

27142714
selectNextErrorOrWarning();
27152715
expect(state).toMatchInlineSnapshot(`
2716-
3, ⚠ 0
2716+
2, ⚠ 0
27172717
[root]
27182718
→ ▾ <ErrorBoundary> ✕
27192719
<Child> ✕

packages/react-dom/src/__tests__/refs-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,8 +499,8 @@ describe('creating element with string ref in constructor', () => {
499499
}
500500
}
501501

502-
// @gate !disableStringRefs
503-
it('throws an error', async () => {
502+
// @gate !disableStringRefs && !__DEV__
503+
it('throws an error in prod', async () => {
504504
await expect(async function () {
505505
const container = document.createElement('div');
506506
const root = ReactDOMClient.createRoot(container);

packages/react-dom/src/client/ReactDOMRootFB.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ import {LegacyRoot} from 'react-reconciler/src/ReactRootTags';
6161
import getComponentNameFromType from 'shared/getComponentNameFromType';
6262
import {has as hasInstance} from 'shared/ReactInstanceMap';
6363

64-
import {currentOwner} from 'react-reconciler/src/ReactFiberCurrentOwner';
64+
import {
65+
current as currentOwner,
66+
isRendering,
67+
} from 'react-reconciler/src/ReactCurrentFiber';
6568

6669
import assign from 'shared/assign';
6770

@@ -343,7 +346,7 @@ export function findDOMNode(
343346
): null | Element | Text {
344347
if (__DEV__) {
345348
const owner = currentOwner;
346-
if (owner !== null && owner.stateNode !== null) {
349+
if (owner !== null && isRendering && owner.stateNode !== null) {
347350
const warnedAboutRefsInRender = owner.stateNode._warnedAboutRefsInRender;
348351
if (!warnedAboutRefsInRender) {
349352
console.error(

packages/react-native-renderer/src/ReactNativePublicCompat.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,17 @@ import {
2525
} from 'react-reconciler/src/ReactFiberReconciler';
2626
import {doesFiberContain} from 'react-reconciler/src/ReactFiberTreeReflection';
2727
import getComponentNameFromType from 'shared/getComponentNameFromType';
28-
import {currentOwner} from 'react-reconciler/src/ReactFiberCurrentOwner';
28+
import {
29+
current as currentOwner,
30+
isRendering,
31+
} from 'react-reconciler/src/ReactCurrentFiber';
2932

3033
export function findHostInstance_DEPRECATED<TElementType: ElementType>(
3134
componentOrHandle: ?(ElementRef<TElementType> | number),
3235
): ?ElementRef<HostComponent<mixed>> {
3336
if (__DEV__) {
3437
const owner = currentOwner;
35-
if (owner !== null && owner.stateNode !== null) {
38+
if (owner !== null && isRendering && owner.stateNode !== null) {
3639
if (!owner.stateNode._warnedAboutRefsInRender) {
3740
console.error(
3841
'%s is accessing findNodeHandle inside its render(). ' +

packages/react-reconciler/src/ReactCurrentFiber.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,33 @@ function getCurrentFiberStackInDev(): string {
4141
return '';
4242
}
4343

44+
export function resetCurrentDebugFiberInDEV() {
45+
if (__DEV__) {
46+
resetCurrentFiber();
47+
}
48+
}
49+
50+
export function setCurrentDebugFiberInDEV(fiber: Fiber | null) {
51+
if (__DEV__) {
52+
setCurrentFiber(fiber);
53+
}
54+
}
55+
4456
export function resetCurrentFiber() {
4557
if (__DEV__) {
4658
ReactSharedInternals.getCurrentStack = null;
47-
current = null;
4859
isRendering = false;
4960
}
61+
current = null;
5062
}
5163

5264
export function setCurrentFiber(fiber: Fiber | null) {
5365
if (__DEV__) {
5466
ReactSharedInternals.getCurrentStack =
5567
fiber === null ? null : getCurrentFiberStackInDev;
56-
current = fiber;
5768
isRendering = false;
5869
}
70+
current = fiber;
5971
}
6072

6173
export function getCurrentFiber(): Fiber | null {

packages/react-reconciler/src/ReactFiberAsyncDispatcher.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {CacheContext} from './ReactFiberCacheComponent';
1616

1717
import {disableStringRefs} from 'shared/ReactFeatureFlags';
1818

19-
import {currentOwner} from './ReactFiberCurrentOwner';
19+
import {current as currentOwner} from './ReactCurrentFiber';
2020

2121
function getCacheForType<T>(resourceType: () => T): T {
2222
if (!enableCache) {

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ import {
125125
import {
126126
getCurrentFiberOwnerNameInDevOrNull,
127127
setIsRendering,
128+
setCurrentFiber,
128129
} from './ReactCurrentFiber';
129130
import {
130131
resolveFunctionForHotReloading,
@@ -296,7 +297,6 @@ import {
296297
pushRootMarkerInstance,
297298
TransitionTracingMarker,
298299
} from './ReactFiberTracingMarkerComponent';
299-
import {setCurrentOwner} from './ReactFiberCurrentOwner';
300300

301301
// A special exception that's used to unwind the stack when an update flows
302302
// into a dehydrated boundary.
@@ -432,7 +432,6 @@ function updateForwardRef(
432432
markComponentRenderStarted(workInProgress);
433433
}
434434
if (__DEV__) {
435-
setCurrentOwner(workInProgress);
436435
setIsRendering(true);
437436
nextChildren = renderWithHooks(
438437
current,
@@ -1150,7 +1149,6 @@ function updateFunctionComponent(
11501149
markComponentRenderStarted(workInProgress);
11511150
}
11521151
if (__DEV__) {
1153-
setCurrentOwner(workInProgress);
11541152
setIsRendering(true);
11551153
nextChildren = renderWithHooks(
11561154
current,
@@ -1373,7 +1371,7 @@ function finishClassComponent(
13731371

13741372
// Rerender
13751373
if (__DEV__ || !disableStringRefs) {
1376-
setCurrentOwner(workInProgress);
1374+
setCurrentFiber(workInProgress);
13771375
}
13781376
let nextChildren;
13791377
if (
@@ -3419,7 +3417,6 @@ function updateContextConsumer(
34193417
}
34203418
let newChildren;
34213419
if (__DEV__) {
3422-
setCurrentOwner(workInProgress);
34233420
setIsRendering(true);
34243421
newChildren = render(newValue);
34253422
setIsRendering(false);

packages/react-reconciler/src/ReactFiberCommitWork.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ import {
101101
} from './ReactFiberFlags';
102102
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
103103
import {
104-
resetCurrentFiber as resetCurrentDebugFiberInDEV,
105-
setCurrentFiber as setCurrentDebugFiberInDEV,
104+
resetCurrentDebugFiberInDEV,
105+
setCurrentDebugFiberInDEV,
106106
getCurrentFiber as getCurrentDebugFiberInDEV,
107107
} from './ReactCurrentFiber';
108108
import {resolveClassComponentProps} from './ReactFiberClassComponent';
@@ -2486,7 +2486,7 @@ export function commitMutationEffects(
24862486

24872487
setCurrentDebugFiberInDEV(finishedWork);
24882488
commitMutationEffectsOnFiber(finishedWork, root, committedLanes);
2489-
setCurrentDebugFiberInDEV(finishedWork);
2489+
resetCurrentDebugFiberInDEV();
24902490

24912491
inProgressLanes = null;
24922492
inProgressRoot = null;
@@ -3125,8 +3125,10 @@ export function commitLayoutEffects(
31253125
inProgressLanes = committedLanes;
31263126
inProgressRoot = root;
31273127

3128+
setCurrentDebugFiberInDEV(finishedWork);
31283129
const current = finishedWork.alternate;
31293130
commitLayoutEffectOnFiber(root, current, finishedWork, committedLanes);
3131+
resetCurrentDebugFiberInDEV();
31303132

31313133
inProgressLanes = null;
31323134
inProgressRoot = null;

packages/react-reconciler/src/ReactFiberCurrentOwner.js

Lines changed: 0 additions & 16 deletions
This file was deleted.

packages/react-reconciler/src/ReactFiberReconciler.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ import {
7878
import {
7979
isRendering as ReactCurrentFiberIsRendering,
8080
current as ReactCurrentFiberCurrent,
81-
resetCurrentFiber as resetCurrentDebugFiberInDEV,
82-
setCurrentFiber as setCurrentDebugFiberInDEV,
81+
resetCurrentDebugFiberInDEV,
82+
setCurrentDebugFiberInDEV,
8383
} from './ReactCurrentFiber';
8484
import {StrictLegacyMode} from './ReactTypeOfMode';
8585
import {

packages/react-reconciler/src/ReactFiberTreeReflection.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
SuspenseComponent,
2525
} from './ReactWorkTags';
2626
import {NoFlags, Placement, Hydrating} from './ReactFiberFlags';
27-
import {currentOwner} from './ReactFiberCurrentOwner';
27+
import {current as currentOwner, isRendering} from './ReactCurrentFiber';
2828

2929
export function getNearestMountedFiber(fiber: Fiber): null | Fiber {
3030
let node = fiber;
@@ -90,7 +90,7 @@ export function isFiberMounted(fiber: Fiber): boolean {
9090
export function isMounted(component: React$Component<any, any>): boolean {
9191
if (__DEV__) {
9292
const owner = currentOwner;
93-
if (owner !== null && owner.tag === ClassComponent) {
93+
if (owner !== null && isRendering && owner.tag === ClassComponent) {
9494
const ownerFiber: Fiber = owner;
9595
const instance = ownerFiber.stateNode;
9696
if (!instance._warnedAboutRefsInRender) {

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ import {
206206
ContextOnlyDispatcher,
207207
} from './ReactFiberHooks';
208208
import {DefaultAsyncDispatcher} from './ReactFiberAsyncDispatcher';
209-
import {setCurrentOwner} from './ReactFiberCurrentOwner';
210209
import {
211210
createCapturedValueAtFiber,
212211
type CapturedValue,
@@ -232,8 +231,9 @@ import ReactStrictModeWarnings from './ReactStrictModeWarnings';
232231
import {
233232
isRendering as ReactCurrentDebugFiberIsRenderingInDEV,
234233
current as ReactCurrentFiberCurrent,
235-
resetCurrentFiber as resetCurrentDebugFiberInDEV,
236-
setCurrentFiber as setCurrentDebugFiberInDEV,
234+
resetCurrentDebugFiberInDEV,
235+
setCurrentDebugFiberInDEV,
236+
resetCurrentFiber,
237237
} from './ReactCurrentFiber';
238238
import {
239239
isDevToolsPresent,
@@ -1686,9 +1686,8 @@ function handleThrow(root: FiberRoot, thrownValue: any): void {
16861686
// These should be reset immediately because they're only supposed to be set
16871687
// when React is executing user code.
16881688
resetHooksAfterThrow();
1689-
resetCurrentDebugFiberInDEV();
16901689
if (__DEV__ || !disableStringRefs) {
1691-
setCurrentOwner(null);
1690+
resetCurrentFiber();
16921691
}
16931692

16941693
if (thrownValue === SuspenseException) {
@@ -2386,18 +2385,16 @@ function performUnitOfWork(unitOfWork: Fiber): void {
23862385
next = beginWork(current, unitOfWork, entangledRenderLanes);
23872386
}
23882387

2389-
resetCurrentDebugFiberInDEV();
2388+
if (__DEV__ || !disableStringRefs) {
2389+
resetCurrentFiber();
2390+
}
23902391
unitOfWork.memoizedProps = unitOfWork.pendingProps;
23912392
if (next === null) {
23922393
// If this doesn't spawn new work, complete the current work.
23932394
completeUnitOfWork(unitOfWork);
23942395
} else {
23952396
workInProgress = next;
23962397
}
2397-
2398-
if (__DEV__ || !disableStringRefs) {
2399-
setCurrentOwner(null);
2400-
}
24012398
}
24022399

24032400
function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
@@ -2408,7 +2405,6 @@ function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
24082405
setCurrentDebugFiberInDEV(unitOfWork);
24092406

24102407
let next;
2411-
setCurrentDebugFiberInDEV(unitOfWork);
24122408
const isProfilingMode =
24132409
enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode;
24142410
if (isProfilingMode) {
@@ -2501,18 +2497,16 @@ function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
25012497
// The begin phase finished successfully without suspending. Return to the
25022498
// normal work loop.
25032499

2504-
resetCurrentDebugFiberInDEV();
2500+
if (__DEV__ || !disableStringRefs) {
2501+
resetCurrentFiber();
2502+
}
25052503
unitOfWork.memoizedProps = unitOfWork.pendingProps;
25062504
if (next === null) {
25072505
// If this doesn't spawn new work, complete the current work.
25082506
completeUnitOfWork(unitOfWork);
25092507
} else {
25102508
workInProgress = next;
25112509
}
2512-
2513-
if (__DEV__ || !disableStringRefs) {
2514-
setCurrentOwner(null);
2515-
}
25162510
}
25172511

25182512
function throwAndUnwindWorkLoop(
@@ -2902,11 +2896,6 @@ function commitRootImpl(
29022896
const prevExecutionContext = executionContext;
29032897
executionContext |= CommitContext;
29042898

2905-
// Reset this to null before calling lifecycles
2906-
if (__DEV__ || !disableStringRefs) {
2907-
setCurrentOwner(null);
2908-
}
2909-
29102899
// The commit phase is broken into several sub-phases. We do a separate pass
29112900
// of the effect list for each phase: all mutation effects come before all
29122901
// layout effects, and so on.

packages/react-reconciler/src/ReactStrictModeWarnings.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
import type {Fiber} from './ReactInternalTypes';
1111

1212
import {
13-
resetCurrentFiber as resetCurrentDebugFiberInDEV,
14-
setCurrentFiber as setCurrentDebugFiberInDEV,
13+
resetCurrentDebugFiberInDEV,
14+
setCurrentDebugFiberInDEV,
1515
} from './ReactCurrentFiber';
1616
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
1717
import {StrictLegacyMode} from './ReactTypeOfMode';

0 commit comments

Comments
 (0)