diff --git a/packages/react-reconciler/src/ReactChildFiber.new.js b/packages/react-reconciler/src/ReactChildFiber.new.js index efdad894e6fe3..4c7a9d62c4713 100644 --- a/packages/react-reconciler/src/ReactChildFiber.new.js +++ b/packages/react-reconciler/src/ReactChildFiber.new.js @@ -34,7 +34,6 @@ import { createFiberFromText, createFiberFromPortal, } from './ReactFiber.new'; -import {emptyRefsObject} from './ReactFiberClassComponent.new'; import {isCompatibleFamilyForHotReloading} from './ReactFiberHotReloading.new'; import {StrictLegacyMode} from './ReactTypeOfMode'; import {getIsHydrating} from './ReactFiberHydrationContext.new'; @@ -199,11 +198,7 @@ function coerceRef( return current.ref; } const ref = function(value) { - let refs = resolvedInst.refs; - if (refs === emptyRefsObject) { - // This is a lazy pooled frozen object, so we need to initialize. - refs = resolvedInst.refs = {}; - } + const refs = resolvedInst.refs; if (value === null) { delete refs[stringRef]; } else { diff --git a/packages/react-reconciler/src/ReactChildFiber.old.js b/packages/react-reconciler/src/ReactChildFiber.old.js index 6f209967071b9..9b2ba7706ed45 100644 --- a/packages/react-reconciler/src/ReactChildFiber.old.js +++ b/packages/react-reconciler/src/ReactChildFiber.old.js @@ -34,7 +34,6 @@ import { createFiberFromText, createFiberFromPortal, } from './ReactFiber.old'; -import {emptyRefsObject} from './ReactFiberClassComponent.old'; import {isCompatibleFamilyForHotReloading} from './ReactFiberHotReloading.old'; import {StrictLegacyMode} from './ReactTypeOfMode'; import {getIsHydrating} from './ReactFiberHydrationContext.old'; @@ -199,11 +198,7 @@ function coerceRef( return current.ref; } const ref = function(value) { - let refs = resolvedInst.refs; - if (refs === emptyRefsObject) { - // This is a lazy pooled frozen object, so we need to initialize. - refs = resolvedInst.refs = {}; - } + const refs = resolvedInst.refs; if (value === null) { delete refs[stringRef]; } else { diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.new.js b/packages/react-reconciler/src/ReactFiberClassComponent.new.js index fe1aea87f0687..e728ca92207a9 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.new.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.new.js @@ -12,7 +12,6 @@ import type {Lanes} from './ReactFiberLane.new'; import type {UpdateQueue} from './ReactFiberClassUpdateQueue.new'; import type {Flags} from './ReactFiberFlags'; -import * as React from 'react'; import { LayoutStatic, MountLayoutDev, @@ -82,10 +81,6 @@ import { const fakeInternalInstance = {}; -// React.Component uses a shared frozen object by default. -// We'll use it to determine whether we need to initialize legacy refs. -export const emptyRefsObject = new React.Component().refs; - let didWarnAboutStateAssignmentForComponent; let didWarnAboutUninitializedState; let didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; @@ -871,7 +866,7 @@ function mountClassInstance( const instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = emptyRefsObject; + instance.refs = {}; initializeUpdateQueue(workInProgress); diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.old.js b/packages/react-reconciler/src/ReactFiberClassComponent.old.js index b4ad1602dadf5..9b0f297cc1c6e 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.old.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.old.js @@ -12,7 +12,6 @@ import type {Lanes} from './ReactFiberLane.old'; import type {UpdateQueue} from './ReactFiberClassUpdateQueue.old'; import type {Flags} from './ReactFiberFlags'; -import * as React from 'react'; import { LayoutStatic, MountLayoutDev, @@ -82,10 +81,6 @@ import { const fakeInternalInstance = {}; -// React.Component uses a shared frozen object by default. -// We'll use it to determine whether we need to initialize legacy refs. -export const emptyRefsObject = new React.Component().refs; - let didWarnAboutStateAssignmentForComponent; let didWarnAboutUninitializedState; let didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; @@ -871,7 +866,7 @@ function mountClassInstance( const instance = workInProgress.stateNode; instance.props = newProps; instance.state = workInProgress.memoizedState; - instance.refs = emptyRefsObject; + instance.refs = {}; initializeUpdateQueue(workInProgress); diff --git a/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js new file mode 100644 index 0000000000000..db07afd8634f8 --- /dev/null +++ b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js @@ -0,0 +1,74 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails react-core + */ + +'use strict'; + +let React; +let ReactNoop; +let act; + +describe('ReactFiberRefs', () => { + beforeEach(() => { + jest.resetModules(); + React = require('react'); + ReactNoop = require('react-noop-renderer'); + act = require('jest-react').act; + }); + + test('strings refs can be codemodded to callback refs', async () => { + let app; + class App extends React.Component { + render() { + app = this; + return ( +
{ + // `refs` used to be a shared frozen object unless/until a string + // ref attached by the reconciler, but it's not anymore so that we + // can codemod string refs to userspace callback refs. + this.refs.div = el; + }} + /> + ); + } + } + + const root = ReactNoop.createRoot(); + await act(async () => root.render()); + expect(app.refs.div.prop).toBe('Hello!'); + }); + + test('class refs are initialized to a frozen shared object', async () => { + const refsCollection = new Set(); + class Component extends React.Component { + constructor(props) { + super(props); + refsCollection.add(this.refs); + } + render() { + return
; + } + } + + const root = ReactNoop.createRoot(); + await act(() => + root.render( + <> + + + , + ), + ); + + expect(refsCollection.size).toBe(1); + const refsInstance = Array.from(refsCollection)[0]; + expect(Object.isFrozen(refsInstance)).toBe(__DEV__); + }); +});