diff --git a/packages/jest-react/src/JestReact.js b/packages/jest-react/src/JestReact.js
index 8fcec97f63f7..3cb9ab88f32f 100644
--- a/packages/jest-react/src/JestReact.js
+++ b/packages/jest-react/src/JestReact.js
@@ -6,7 +6,6 @@
*/
import {REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols';
-import {disableStringRefs} from 'shared/ReactFeatureFlags';
const {assertConsoleLogsCleared} = require('internal-test-utils/consoleMock');
import isArray from 'shared/isArray';
@@ -56,14 +55,6 @@ function createJSXElementForTestComparison(type, props) {
value: null,
});
return element;
- } else if (!__DEV__ && disableStringRefs) {
- return {
- $$typeof: REACT_ELEMENT_TYPE,
- type: type,
- key: null,
- ref: null,
- props: props,
- };
} else {
return {
$$typeof: REACT_ELEMENT_TYPE,
@@ -71,8 +62,6 @@ function createJSXElementForTestComparison(type, props) {
key: null,
ref: null,
props: props,
- _owner: null,
- _store: __DEV__ ? {} : undefined,
};
}
}
diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js
index 6c370bd2ef65..9a3d3e019867 100644
--- a/packages/react-client/src/ReactFlightClient.js
+++ b/packages/react-client/src/ReactFlightClient.js
@@ -41,7 +41,6 @@ import type {Postpone} from 'react/src/ReactPostpone';
import type {TemporaryReferenceSet} from './ReactFlightTemporaryReferences';
import {
- disableStringRefs,
enableBinaryFlight,
enablePostpone,
enableFlightReadableStream,
@@ -688,16 +687,6 @@ function createElement(
enumerable: false,
get: nullRefGetter,
});
- } else if (!__DEV__ && disableStringRefs) {
- element = ({
- // This tag allows us to uniquely identify this as a React Element
- $$typeof: REACT_ELEMENT_TYPE,
-
- type,
- key,
- ref: null,
- props,
- }: any);
} else {
element = ({
// This tag allows us to uniquely identify this as a React Element
@@ -707,9 +696,6 @@ function createElement(
key,
ref: null,
props,
-
- // Record the component responsible for creating this element.
- _owner: __DEV__ && owner === null ? response._debugRootOwner : owner,
}: any);
}
diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js
index 47c6db808f04..dc33d03f9426 100644
--- a/packages/react-client/src/__tests__/ReactFlight-test.js
+++ b/packages/react-client/src/__tests__/ReactFlight-test.js
@@ -3268,9 +3268,7 @@ describe('ReactFlight', () => {
expect(greeting._owner).toBe(greeting._debugInfo[0]);
} else {
expect(greeting._debugInfo).toBe(undefined);
- expect(greeting._owner).toBe(
- gate(flags => flags.disableStringRefs) ? undefined : null,
- );
+ expect(greeting._owner).toBe(undefined);
}
ReactNoop.render(greeting);
});
diff --git a/packages/react-dom/src/__tests__/ReactComponent-test.js b/packages/react-dom/src/__tests__/ReactComponent-test.js
index 9b2f443a7c34..645911469754 100644
--- a/packages/react-dom/src/__tests__/ReactComponent-test.js
+++ b/packages/react-dom/src/__tests__/ReactComponent-test.js
@@ -42,19 +42,6 @@ describe('ReactComponent', () => {
}).toThrowError(/Target container is not a DOM element./);
});
- // @gate !disableStringRefs
- it('should throw when supplying a string ref outside of render method', async () => {
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
- await expect(
- act(() => {
- root.render(
);
- }),
- // TODO: This throws an AggregateError. Need to update test infra to
- // support matching against AggregateError.
- ).rejects.toThrow();
- });
-
it('should throw (in dev) when children are mutated during render', async () => {
function Wrapper(props) {
props.children[1] = ; // Mutation is illegal
@@ -132,105 +119,6 @@ describe('ReactComponent', () => {
}
});
- // @gate !disableStringRefs
- it('string refs do not detach and reattach on every render', async () => {
- let refVal;
- class Child extends React.Component {
- componentDidUpdate() {
- // The parent ref should still be attached because it hasn't changed
- // since the last render. If the ref had changed, then this would be
- // undefined because refs are attached during the same phase (layout)
- // as componentDidUpdate, in child -> parent order. So the new parent
- // ref wouldn't have attached yet.
- refVal = this.props.contextRef();
- }
-
- render() {
- if (this.props.show) {
- return child
;
- }
- }
- }
-
- class Parent extends React.Component {
- render() {
- return (
-
- this.refs.root}
- show={this.props.showChild}
- />
-
- );
- }
- }
-
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
-
- await act(() => {
- root.render();
- });
-
- assertConsoleErrorDev(['contains the string ref']);
-
- expect(refVal).toBe(undefined);
- await act(() => {
- root.render();
- });
- expect(refVal).toBe(container.querySelector('#test-root'));
- });
-
- // @gate !disableStringRefs
- it('should support string refs on owned components', async () => {
- const innerObj = {};
- const outerObj = {};
-
- class Wrapper extends React.Component {
- getObject = () => {
- return this.props.object;
- };
-
- render() {
- return {this.props.children}
;
- }
- }
-
- class Component extends React.Component {
- render() {
- const inner = ;
- const outer = (
-
- {inner}
-
- );
- return outer;
- }
-
- componentDidMount() {
- expect(this.refs.inner.getObject()).toEqual(innerObj);
- expect(this.refs.outer.getObject()).toEqual(outerObj);
- }
- }
-
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
- await expect(async () => {
- await act(() => {
- root.render();
- });
- }).toErrorDev([
- 'Component "Component" contains the string ref "inner". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in Wrapper (at **)\n' +
- ' in div (at **)\n' +
- ' in Wrapper (at **)\n' +
- ' in Component (at **)',
- ]);
- });
-
it('should not have string refs on unmounted components', async () => {
class Parent extends React.Component {
render() {
diff --git a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js
index 89d0b83abc3b..444407668120 100644
--- a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js
+++ b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js
@@ -537,11 +537,8 @@ describe('ReactCompositeComponent', () => {
});
it('should cleanup even if render() fatals', async () => {
- const dispatcherEnabled =
- __DEV__ ||
- !gate(flags => flags.disableStringRefs) ||
- gate(flags => flags.enableCache);
- const ownerEnabled = __DEV__ || !gate(flags => flags.disableStringRefs);
+ const dispatcherEnabled = __DEV__ || gate(flags => flags.enableCache);
+ const ownerEnabled = __DEV__;
let stashedDispatcher;
class BadComponent extends React.Component {
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
index b8d1a0716ae5..9094af348472 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
@@ -29,12 +29,8 @@ function initModules() {
};
}
-const {
- resetModules,
- asyncReactDOMRender,
- clientRenderOnServerString,
- expectMarkupMatch,
-} = ReactDOMServerIntegrationUtils(initModules);
+const {resetModules, clientRenderOnServerString, expectMarkupMatch} =
+ ReactDOMServerIntegrationUtils(initModules);
describe('ReactDOMServerIntegration', () => {
beforeEach(() => {
@@ -75,36 +71,6 @@ describe('ReactDOMServerIntegration', () => {
expect(refElement).not.toBe(null);
expect(refElement).toBe(e);
});
-
- // @gate !disableStringRefs
- it('should have string refs on client when rendered over server markup', async () => {
- class RefsComponent extends React.Component {
- render() {
- return ;
- }
- }
-
- const markup = ReactDOMServer.renderToString();
- const root = document.createElement('div');
- root.innerHTML = markup;
- let component = null;
- resetModules();
- await expect(async () => {
- await asyncReactDOMRender(
- (component = e)} />,
- root,
- true,
- );
- }).toErrorDev([
- 'Component "RefsComponent" contains the string ref "myDiv". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in div (at **)\n' +
- ' in RefsComponent (at **)',
- ]);
- expect(component.refs.myDiv).toBe(root.firstChild);
- });
});
it('should forward refs', async () => {
diff --git a/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js b/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js
index 77c9e1886e0a..e0022dd99004 100644
--- a/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js
+++ b/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js
@@ -11,7 +11,6 @@
let React;
let ReactNoop;
-let JSXDEVRuntime;
let waitForAll;
describe('ReactDeprecationWarnings', () => {
@@ -21,9 +20,6 @@ describe('ReactDeprecationWarnings', () => {
ReactNoop = require('react-noop-renderer');
const InternalTestUtils = require('internal-test-utils');
waitForAll = InternalTestUtils.waitForAll;
- if (__DEV__) {
- JSXDEVRuntime = require('react/jsx-dev-runtime');
- }
});
// @gate !disableDefaultPropsExceptForClasses || !__DEV__
@@ -65,117 +61,4 @@ describe('ReactDeprecationWarnings', () => {
'release. Use JavaScript default parameters instead.',
);
});
-
- // @gate !disableStringRefs
- it('should warn when given string refs', async () => {
- class RefComponent extends React.Component {
- render() {
- return null;
- }
- }
- class Component extends React.Component {
- render() {
- return ;
- }
- }
-
- ReactNoop.render();
- await expect(async () => await waitForAll([])).toErrorDev(
- 'Component "Component" contains the string ref "refComponent". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: ' +
- 'https://react.dev/link/strict-mode-string-ref' +
- '\n in RefComponent (at **)' +
- '\n in Component (at **)',
- );
- });
-
- // Disabling this until #28732 lands so we can assert on the warning message.
- // (It's already disabled in all but the Meta builds, anyway. Nbd.)
- // @gate TODO || !__DEV__
- // @gate !disableStringRefs
- it('should warn when owner and self are the same for string refs', async () => {
- class RefComponent extends React.Component {
- render() {
- return null;
- }
- }
- class Component extends React.Component {
- render() {
- return React.createElement(RefComponent, {
- ref: 'refComponent',
- __self: this,
- });
- }
- }
-
- ReactNoop.render();
- await expect(async () => await waitForAll([])).toErrorDev([
- 'Component "Component" contains the string ref "refComponent". Support for string refs will be removed in a future major release.',
- ]);
- await waitForAll([]);
- });
-
- // Disabling this until #28732 lands so we can assert on the warning message.
- // (It's already disabled in all but the Meta builds, anyway. Nbd.)
- // @gate TODO || !__DEV__
- // @gate !disableStringRefs
- it('should warn when owner and self are different for string refs (createElement)', async () => {
- class RefComponent extends React.Component {
- render() {
- return null;
- }
- }
- class Component extends React.Component {
- render() {
- return React.createElement(RefComponent, {
- ref: 'refComponent',
- __self: {},
- });
- }
- }
-
- ReactNoop.render();
- await expect(async () => await waitForAll([])).toErrorDev([
- 'Component "Component" contains the string ref "refComponent". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'This case cannot be automatically converted to an arrow function. ' +
- 'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: ' +
- 'https://react.dev/link/strict-mode-string-ref',
- ]);
- });
-
- // @gate __DEV__
- // @gate !disableStringRefs
- it('should warn when owner and self are different for string refs (jsx)', async () => {
- class RefComponent extends React.Component {
- render() {
- return null;
- }
- }
- class Component extends React.Component {
- render() {
- return JSXDEVRuntime.jsxDEV(
- RefComponent,
- {ref: 'refComponent'},
- null,
- false,
- {},
- {},
- );
- }
- }
-
- ReactNoop.render();
- await expect(async () => await waitForAll([])).toErrorDev([
- 'Component "Component" contains the string ref "refComponent". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'This case cannot be automatically converted to an arrow function. ' +
- 'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: ' +
- 'https://react.dev/link/strict-mode-string-ref',
- ]);
- });
});
diff --git a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
index 24f97520ecc3..f1250ce26d7c 100644
--- a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
+++ b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
@@ -179,24 +179,6 @@ describe('ReactFunctionComponent', () => {
).resolves.not.toThrowError();
});
- // @gate !disableStringRefs
- it('should throw on string refs in pure functions', async () => {
- function Child() {
- return ;
- }
-
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
- await expect(
- act(() => {
- root.render();
- }),
- )
- // TODO: This throws an AggregateError. Need to update test infra to
- // support matching against AggregateError.
- .rejects.toThrowError();
- });
-
it('should use correct name in key warning', async () => {
function Child() {
return {[]}
;
diff --git a/packages/react-dom/src/__tests__/multiple-copies-of-react-test.js b/packages/react-dom/src/__tests__/multiple-copies-of-react-test.js
deleted file mode 100644
index 2d107cbb1970..000000000000
--- a/packages/react-dom/src/__tests__/multiple-copies-of-react-test.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * 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 = require('react');
-const ReactDOMClient = require('react-dom/client');
-const act = require('internal-test-utils').act;
-
-class TextWithStringRef extends React.Component {
- render() {
- jest.resetModules();
- React = require('react');
- return Hello world!;
- }
-}
-
-describe('when different React version is used with string ref', () => {
- // @gate !disableStringRefs
- it('throws the "Refs must have owner" warning', async () => {
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
- await expect(
- act(() => {
- root.render();
- }),
- )
- // TODO: This throws an AggregateError. Need to update test infra to
- // support matching against AggregateError.
- .rejects.toThrow();
- });
-});
diff --git a/packages/react-dom/src/__tests__/refs-test.js b/packages/react-dom/src/__tests__/refs-test.js
index 80ea8d1e26b3..b80f8b27753f 100644
--- a/packages/react-dom/src/__tests__/refs-test.js
+++ b/packages/react-dom/src/__tests__/refs-test.js
@@ -13,179 +13,6 @@ const React = require('react');
const ReactDOMClient = require('react-dom/client');
const act = require('internal-test-utils').act;
-// This is testing if string refs are deleted from `instance.refs`
-// Once support for string refs is removed, this test can be removed.
-// Detaching is already tested in refs-detruction-test.js
-describe('reactiverefs', () => {
- let container;
-
- afterEach(() => {
- if (container) {
- document.body.removeChild(container);
- container = null;
- }
- });
-
- /**
- * Counts clicks and has a renders an item for each click. Each item rendered
- * has a ref of the form "clickLogN".
- */
- class ClickCounter extends React.Component {
- state = {count: this.props.initialCount};
-
- triggerReset = () => {
- this.setState({count: this.props.initialCount});
- };
-
- handleClick = () => {
- this.setState({count: this.state.count + 1});
- };
-
- render() {
- const children = [];
- let i;
- for (i = 0; i < this.state.count; i++) {
- children.push(
- ,
- );
- }
- return (
-
- {children}
-
- );
- }
- }
-
- const expectClickLogsLengthToBe = function (instance, length) {
- const clickLogs = instance.container.querySelectorAll('.clickLogDiv');
- expect(clickLogs.length).toBe(length);
- expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length);
- };
-
- /**
- * Render a TestRefsComponent and ensure that the main refs are wired up.
- */
- const renderTestRefsComponent = async function () {
- /**
- * Only purpose is to test that refs are tracked even when applied to a
- * component that is injected down several layers. Ref systems are difficult to
- * build in such a way that ownership is maintained in an airtight manner.
- */
- class GeneralContainerComponent extends React.Component {
- render() {
- return {this.props.children}
;
- }
- }
-
- /**
- * Notice how refs ownership is maintained even when injecting a component
- * into a different parent.
- */
- class TestRefsComponent extends React.Component {
- container = null;
- doReset = () => {
- this.refs.myCounter.triggerReset();
- };
-
- render() {
- return (
- (this.container = current)}>
-
- Reset Me By Clicking This.
-
-
-
-
-
- );
- }
- }
-
- container = document.createElement('div');
- document.body.appendChild(container);
-
- let testRefsComponent;
- await expect(async () => {
- const root = ReactDOMClient.createRoot(container);
- await act(() => {
- root.render(
- {
- testRefsComponent = current;
- }}
- />,
- );
- });
- }).toErrorDev([
- 'Component "TestRefsComponent" contains the string ' +
- 'ref "resetDiv". Support for string refs will be removed in a ' +
- 'future major release. We recommend using useRef() or createRef() ' +
- 'instead. Learn more about using refs safely ' +
- 'here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in div (at **)\n' +
- ' in div (at **)\n' +
- ' in TestRefsComponent (at **)',
- 'Component "ClickCounter" contains the string ' +
- 'ref "clickLog0". Support for string refs will be removed in a ' +
- 'future major release. We recommend using useRef() or createRef() ' +
- 'instead. Learn more about using refs safely ' +
- 'here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in div (at **)\n' +
- ' in span (at **)\n' +
- ' in ClickCounter (at **)',
- ]);
-
- expect(testRefsComponent instanceof TestRefsComponent).toBe(true);
-
- const generalContainer = testRefsComponent.refs.myContainer;
- expect(generalContainer instanceof GeneralContainerComponent).toBe(true);
-
- const counter = testRefsComponent.refs.myCounter;
- expect(counter instanceof ClickCounter).toBe(true);
-
- return testRefsComponent;
- };
-
- /**
- * Ensure that for every click log there is a corresponding ref (from the
- * perspective of the injected ClickCounter component.
- */
- // @gate !disableStringRefs
- it('Should increase refs with an increase in divs', async () => {
- const testRefsComponent = await renderTestRefsComponent();
- const clickIncrementer =
- testRefsComponent.container.querySelector('.clickIncrementer');
-
- expectClickLogsLengthToBe(testRefsComponent, 1);
-
- // After clicking the reset, there should still only be one click log ref.
- testRefsComponent.refs.resetDiv.click();
- expectClickLogsLengthToBe(testRefsComponent, 1);
-
- // Begin incrementing clicks (and therefore refs).
- await act(() => {
- clickIncrementer.click();
- });
- expectClickLogsLengthToBe(testRefsComponent, 2);
-
- await act(() => {
- clickIncrementer.click();
- });
- expectClickLogsLengthToBe(testRefsComponent, 3);
-
- // Now reset again
- await act(() => {
- testRefsComponent.refs.resetDiv.click();
- });
- expectClickLogsLengthToBe(testRefsComponent, 1);
- });
-});
-
/**
* Tests that when a ref hops around children, we can track that correctly.
*/
@@ -320,32 +147,6 @@ describe('ref swapping', () => {
expect(refCalled).toBe(1);
});
- // @gate !disableStringRefs
- it('coerces numbers to strings', async () => {
- class A extends React.Component {
- render() {
- return ;
- }
- }
- let a;
- await expect(async () => {
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
-
- await act(() => {
- root.render( (a = current)} />);
- });
- }).toErrorDev([
- 'Component "A" contains the string ref "1". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in div (at **)\n' +
- ' in A (at **)',
- ]);
- expect(a.refs[1].nodeName).toBe('DIV');
- });
-
it('provides an error for invalid refs', async () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
@@ -469,108 +270,6 @@ describe('root level refs', () => {
});
});
-describe('creating element with string ref in constructor', () => {
- class RefTest extends React.Component {
- constructor(props) {
- super(props);
- this.p = Hello!
;
- }
-
- render() {
- return {this.p}
;
- }
- }
-
- // @gate !disableStringRefs && !__DEV__
- it('throws an error in prod', async () => {
- await expect(async function () {
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
-
- await act(() => {
- root.render();
- });
- })
- // TODO: This throws an AggregateError. Need to update test infra to
- // support matching against AggregateError.
- .rejects.toThrowError();
- });
-});
-
-describe('strings refs across renderers', () => {
- // @gate !disableStringRefs
- it('does not break', async () => {
- class Parent extends React.Component {
- render() {
- // This component owns both refs.
- return (
- }
- child2={}
- />
- );
- }
- }
-
- class Indirection extends React.Component {
- componentDidUpdate() {
- // One ref is being rendered later using another renderer copy.
- jest.resetModules();
- const AnotherCopyOfReactDOM = require('react-dom');
- const AnotherCopyOfReactDOMClient = require('react-dom/client');
- const root = AnotherCopyOfReactDOMClient.createRoot(div2);
- AnotherCopyOfReactDOM.flushSync(() => {
- root.render(this.props.child2);
- });
- }
- render() {
- // The other one is being rendered directly.
- return this.props.child1;
- }
- }
-
- const div1 = document.createElement('div');
- const div2 = document.createElement('div');
-
- const root = ReactDOMClient.createRoot(div1);
- let inst;
- await expect(async () => {
- await act(() => {
- root.render(
- {
- if (current !== null) {
- inst = current;
- }
- }}
- />,
- );
- });
- }).toErrorDev([
- 'Component "Parent" contains the string ref "child1". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in div (at **)\n' +
- ' in Indirection (at **)\n' +
- ' in Parent (at **)',
- ]);
-
- // Only the first ref has rendered yet.
- expect(inst.refs.child1.tagName).toBe('DIV');
- expect(inst.refs.child1).toBe(div1.firstChild);
-
- // Now both refs should be rendered.
- await act(() => {
- root.render();
- });
- expect(inst.refs.child1.tagName).toBe('DIV');
- expect(inst.refs.child1).toBe(div1.firstChild);
- expect(inst.refs.child2.tagName).toBe('DIV');
- expect(inst.refs.child2).toBe(div2.firstChild);
- });
-});
-
describe('refs return clean up function', () => {
it('calls clean up function if it exists', async () => {
const container = document.createElement('div');
diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js
index 3e95e537e9dd..4c1bf05e5404 100644
--- a/packages/react-noop-renderer/src/createReactNoop.js
+++ b/packages/react-noop-renderer/src/createReactNoop.js
@@ -35,7 +35,7 @@ import {
ConcurrentRoot,
LegacyRoot,
} from 'react-reconciler/constants';
-import {disableLegacyMode, disableStringRefs} from 'shared/ReactFeatureFlags';
+import {disableLegacyMode} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import ReactVersion from 'shared/ReactVersion';
@@ -843,14 +843,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
value: null,
});
return element;
- } else if (!__DEV__ && disableStringRefs) {
- return {
- $$typeof: REACT_ELEMENT_TYPE,
- type: type,
- key: null,
- ref: null,
- props: props,
- };
} else {
return {
$$typeof: REACT_ELEMENT_TYPE,
@@ -858,8 +850,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
key: null,
ref: null,
props: props,
- _owner: null,
- _store: __DEV__ ? {} : undefined,
};
}
}
diff --git a/packages/react-reconciler/src/ReactFiberAsyncDispatcher.js b/packages/react-reconciler/src/ReactFiberAsyncDispatcher.js
index d329fb369cae..0d6856f5d0ac 100644
--- a/packages/react-reconciler/src/ReactFiberAsyncDispatcher.js
+++ b/packages/react-reconciler/src/ReactFiberAsyncDispatcher.js
@@ -14,8 +14,6 @@ import {enableCache} from 'shared/ReactFeatureFlags';
import {readContext} from './ReactFiberNewContext';
import {CacheContext} from './ReactFiberCacheComponent';
-import {disableStringRefs} from 'shared/ReactFeatureFlags';
-
import {current as currentOwner} from './ReactCurrentFiber';
function getCacheForType(resourceType: () => T): T {
@@ -35,7 +33,7 @@ export const DefaultAsyncDispatcher: AsyncDispatcher = ({
getCacheForType,
}: any);
-if (__DEV__ || !disableStringRefs) {
+if (__DEV__) {
DefaultAsyncDispatcher.getOwner = (): null | Fiber => {
return currentOwner;
};
diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js
index efb34826c970..0a5457d20c33 100644
--- a/packages/react-reconciler/src/ReactFiberBeginWork.js
+++ b/packages/react-reconciler/src/ReactFiberBeginWork.js
@@ -110,7 +110,6 @@ import {
enableRenderableContext,
disableLegacyMode,
disableDefaultPropsExceptForClasses,
- disableStringRefs,
enableOwnerStacks,
} from 'shared/ReactFeatureFlags';
import isArray from 'shared/isArray';
@@ -1052,25 +1051,6 @@ function markRef(current: Fiber | null, workInProgress: Fiber) {
);
}
if (current === null || current.ref !== ref) {
- if (!disableStringRefs && current !== null) {
- const oldRef = current.ref;
- const newRef = ref;
- if (
- typeof oldRef === 'function' &&
- typeof newRef === 'function' &&
- typeof oldRef.__stringRef === 'string' &&
- oldRef.__stringRef === newRef.__stringRef &&
- oldRef.__stringRefType === newRef.__stringRefType &&
- oldRef.__stringRefOwner === newRef.__stringRefOwner
- ) {
- // Although this is a different callback, it represents the same
- // string ref. To avoid breaking old Meta code that relies on string
- // refs only being attached once, reuse the old ref. This will
- // prevent us from detaching and reattaching the ref on each update.
- workInProgress.ref = oldRef;
- return;
- }
- }
// Schedule a Ref effect
workInProgress.flags |= Ref | RefStatic;
}
@@ -1388,7 +1368,7 @@ function finishClassComponent(
const instance = workInProgress.stateNode;
// Rerender
- if (__DEV__ || !disableStringRefs) {
+ if (__DEV__) {
setCurrentFiber(workInProgress);
}
let nextChildren;
diff --git a/packages/react-reconciler/src/ReactFiberCommitEffects.js b/packages/react-reconciler/src/ReactFiberCommitEffects.js
index 4d10c9ee6faf..70c49bc62fae 100644
--- a/packages/react-reconciler/src/ReactFiberCommitEffects.js
+++ b/packages/react-reconciler/src/ReactFiberCommitEffects.js
@@ -18,7 +18,6 @@ import {
enableProfilerNestedUpdatePhase,
enableSchedulingProfiler,
enableScopeAPI,
- disableStringRefs,
} from 'shared/ReactFeatureFlags';
import {
ClassComponent,
@@ -773,7 +772,7 @@ function commitAttachRef(finishedWork: Fiber) {
if (__DEV__) {
// TODO: We should move these warnings to happen during the render
// phase (markRef).
- if (disableStringRefs && typeof ref === 'string') {
+ if (typeof ref === 'string') {
console.error('String refs are no longer supported.');
} else if (!ref.hasOwnProperty('current')) {
console.error(
diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js
index aa5884444063..1ea05dd010a8 100644
--- a/packages/react-reconciler/src/ReactFiberWorkLoop.js
+++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js
@@ -40,7 +40,6 @@ import {
enableInfiniteRenderLoopDetection,
disableLegacyMode,
disableDefaultPropsExceptForClasses,
- disableStringRefs,
enableSiblingPrerendering,
enableComponentPerformanceTrack,
} from 'shared/ReactFeatureFlags';
@@ -1732,7 +1731,7 @@ function handleThrow(root: FiberRoot, thrownValue: any): void {
// These should be reset immediately because they're only supposed to be set
// when React is executing user code.
resetHooksAfterThrow();
- if (__DEV__ || !disableStringRefs) {
+ if (__DEV__) {
resetCurrentFiber();
}
@@ -1928,7 +1927,7 @@ function popDispatcher(prevDispatcher: any) {
}
function pushAsyncDispatcher() {
- if (enableCache || __DEV__ || !disableStringRefs) {
+ if (enableCache || __DEV__) {
const prevAsyncDispatcher = ReactSharedInternals.A;
ReactSharedInternals.A = DefaultAsyncDispatcher;
return prevAsyncDispatcher;
@@ -1938,7 +1937,7 @@ function pushAsyncDispatcher() {
}
function popAsyncDispatcher(prevAsyncDispatcher: any) {
- if (enableCache || __DEV__ || !disableStringRefs) {
+ if (enableCache || __DEV__) {
ReactSharedInternals.A = prevAsyncDispatcher;
}
}
@@ -2497,9 +2496,6 @@ function performUnitOfWork(unitOfWork: Fiber): void {
}
}
- if (!disableStringRefs) {
- resetCurrentFiber();
- }
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// If this doesn't spawn new work, complete the current work.
@@ -2519,11 +2515,6 @@ function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
next = replayBeginWork(unitOfWork);
}
- // The begin phase finished successfully without suspending. Return to the
- // normal work loop.
- if (!disableStringRefs) {
- resetCurrentFiber();
- }
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// If this doesn't spawn new work, complete the current work.
diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js
index 1c98a9e9c7fb..d91727525c96 100644
--- a/packages/react-reconciler/src/ReactInternalTypes.js
+++ b/packages/react-reconciler/src/ReactInternalTypes.js
@@ -460,6 +460,6 @@ export type Dispatcher = {
export type AsyncDispatcher = {
getCacheForType: (resourceType: () => T) => T,
- // DEV-only (or !disableStringRefs)
+ // DEV-only
getOwner: () => null | Fiber | ReactComponentInfo | ComponentStackNode,
};
diff --git a/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js
index 8fd5206c94ae..78409c8e2a4e 100644
--- a/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js
@@ -85,35 +85,6 @@ describe('ReactFiberRefs', () => {
expect(ref2.current).not.toBe(null);
});
- // @gate !disableStringRefs
- it('string ref props are converted to function refs', async () => {
- let refProp;
- function Child({ref}) {
- refProp = ref;
- return ;
- }
-
- let owner;
- class Owner extends React.Component {
- render() {
- owner = this;
- return ;
- }
- }
-
- const root = ReactNoop.createRoot();
- await act(() => root.render());
-
- // When string refs aren't disabled, string refs
- // the receiving component receives a callback ref, not the original string.
- // This behavior should never be shipped to open source; it's only here to
- // allow Meta to keep using string refs temporarily while they finish
- // migrating their codebase.
- expect(typeof refProp === 'function').toBe(true);
- expect(owner.refs.child.type).toBe('div');
- });
-
- // @gate disableStringRefs
it('throw if a string ref is passed to a ref-receiving component', async () => {
let refProp;
function Child({ref}) {
diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js
index 81f892b48e35..c4473c1774e9 100644
--- a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js
@@ -1334,38 +1334,4 @@ describe('ReactIncrementalSideEffects', () => {
// TODO: Test that mounts, updates, refs, unmounts and deletions happen in the
// expected way for aborted and resumed render life-cycles.
-
- // @gate !disableStringRefs
- it('supports string refs', async () => {
- let fooInstance = null;
-
- class Bar extends React.Component {
- componentDidMount() {
- this.test = 'test';
- }
- render() {
- return ;
- }
- }
-
- class Foo extends React.Component {
- render() {
- fooInstance = this;
- return ;
- }
- }
-
- ReactNoop.render();
- await expect(async () => {
- await waitForAll([]);
- }).toErrorDev([
- 'Component "Foo" contains the string ref "bar". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in Bar (at **)\n' +
- ' in Foo (at **)',
- ]);
- expect(fooInstance.refs.bar.test).toEqual('test');
- });
});
diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js
index ed349cde81f0..1a097ffbda56 100644
--- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js
+++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js
@@ -1001,9 +1001,7 @@ describe('ReactFlightDOMEdge', () => {
expect(greeting._owner).toBe(lazyWrapper._debugInfo[0]);
} else {
expect(lazyWrapper._debugInfo).toBe(undefined);
- expect(greeting._owner).toBe(
- gate(flags => flags.disableStringRefs) ? undefined : null,
- );
+ expect(greeting._owner).toBe(undefined);
}
});
diff --git a/packages/react-server/src/ReactFizzAsyncDispatcher.js b/packages/react-server/src/ReactFizzAsyncDispatcher.js
index 3a548ae13803..e4d940d463c2 100644
--- a/packages/react-server/src/ReactFizzAsyncDispatcher.js
+++ b/packages/react-server/src/ReactFizzAsyncDispatcher.js
@@ -10,8 +10,6 @@
import type {AsyncDispatcher} from 'react-reconciler/src/ReactInternalTypes';
import type {ComponentStackNode} from './ReactFizzComponentStack';
-import {disableStringRefs} from 'shared/ReactFeatureFlags';
-
import {currentTaskInDEV} from './ReactFizzCurrentTask';
function getCacheForType(resourceType: () => T): T {
@@ -29,8 +27,4 @@ if (__DEV__) {
}
return currentTaskInDEV.componentStack;
};
-} else if (!disableStringRefs) {
- DefaultAsyncDispatcher.getOwner = (): null => {
- return null;
- };
}
diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js
index 7b881fdbe8cc..f245861ba001 100644
--- a/packages/react-server/src/ReactFizzServer.js
+++ b/packages/react-server/src/ReactFizzServer.js
@@ -162,7 +162,6 @@ import {
enableRenderableContext,
disableDefaultPropsExceptForClasses,
enableAsyncIterableChildren,
- disableStringRefs,
enableOwnerStacks,
} from 'shared/ReactFeatureFlags';
@@ -4452,7 +4451,7 @@ export function performWork(request: Request): void {
const prevDispatcher = ReactSharedInternals.H;
ReactSharedInternals.H = HooksDispatcher;
let prevAsyncDispatcher = null;
- if (enableCache || __DEV__ || !disableStringRefs) {
+ if (enableCache || __DEV__) {
prevAsyncDispatcher = ReactSharedInternals.A;
ReactSharedInternals.A = DefaultAsyncDispatcher;
}
diff --git a/packages/react-server/src/flight/ReactFlightAsyncDispatcher.js b/packages/react-server/src/flight/ReactFlightAsyncDispatcher.js
index f5f031a860ff..00c1abf33292 100644
--- a/packages/react-server/src/flight/ReactFlightAsyncDispatcher.js
+++ b/packages/react-server/src/flight/ReactFlightAsyncDispatcher.js
@@ -7,14 +7,9 @@
* @flow
*/
-import type {ReactComponentInfo} from 'shared/ReactTypes';
-
import type {AsyncDispatcher} from 'react-reconciler/src/ReactInternalTypes';
import {resolveRequest, getCache} from '../ReactFlightServer';
-
-import {disableStringRefs} from 'shared/ReactFeatureFlags';
-
import {resolveOwner} from './ReactFlightCurrentOwner';
function resolveCache(): Map {
@@ -40,9 +35,4 @@ export const DefaultAsyncDispatcher: AsyncDispatcher = ({
if (__DEV__) {
DefaultAsyncDispatcher.getOwner = resolveOwner;
-} else if (!disableStringRefs) {
- // Server Components never use string refs but the JSX runtime looks for it.
- DefaultAsyncDispatcher.getOwner = (): null | ReactComponentInfo => {
- return null;
- };
}
diff --git a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee
index 22ef789f4f6e..3ad6aa023518 100644
--- a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee
+++ b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee
@@ -551,25 +551,4 @@ describe 'ReactCoffeeScriptClass', ->
],
)
- if !featureFlags.disableStringRefs
- it 'supports string refs', ->
- class Foo extends React.Component
- render: ->
- React.createElement(InnerComponent,
- name: 'foo'
- ref: 'inner'
- )
-
- ref = React.createRef()
- expect(->
- test(React.createElement(Foo, ref: ref), 'DIV', 'foo')
- ).toErrorDev([
- 'Component "Foo" contains the string ref "inner". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in _Class (at **)'
- ]);
- expect(ref.current.refs.inner.getName()).toBe 'foo'
-
undefined
diff --git a/packages/react/src/__tests__/ReactCreateElement-test.js b/packages/react/src/__tests__/ReactCreateElement-test.js
index 3ab5c34c3304..392f89979e76 100644
--- a/packages/react/src/__tests__/ReactCreateElement-test.js
+++ b/packages/react/src/__tests__/ReactCreateElement-test.js
@@ -218,7 +218,7 @@ describe('ReactCreateElement', () => {
}
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => root.render(React.createElement(Wrapper)));
- if (__DEV__ || !gate(flags => flags.disableStringRefs)) {
+ if (__DEV__) {
expect(element._owner.stateNode).toBe(instance);
} else {
expect('_owner' in element).toBe(false);
diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js
index 3ac0b18e8e75..eceeab18c5bb 100644
--- a/packages/react/src/__tests__/ReactES6Class-test.js
+++ b/packages/react/src/__tests__/ReactES6Class-test.js
@@ -592,25 +592,4 @@ describe('ReactES6Class', () => {
]);
});
}
-
- if (!require('shared/ReactFeatureFlags').disableStringRefs) {
- it('supports string refs', () => {
- class Foo extends React.Component {
- render() {
- return ;
- }
- }
- const ref = React.createRef();
- expect(() => {
- runTest(, 'DIV', 'foo');
- }).toErrorDev([
- 'Component "Foo" contains the string ref "inner". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in Inner (at **)',
- ]);
- expect(ref.current.refs.inner.getName()).toBe('foo');
- });
- }
});
diff --git a/packages/react/src/__tests__/ReactElementClone-test.js b/packages/react/src/__tests__/ReactElementClone-test.js
index 4e7d0c5ca2a2..fb0bfe2df8d6 100644
--- a/packages/react/src/__tests__/ReactElementClone-test.js
+++ b/packages/react/src/__tests__/ReactElementClone-test.js
@@ -270,49 +270,8 @@ describe('ReactElementClone', () => {
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => root.render());
- if (gate(flags => flags.disableStringRefs)) {
- expect(component.childRef).toEqual({current: null});
- expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN');
- } else if (gate(flags => !flags.disableStringRefs)) {
- expect(component.childRef).toEqual({current: null});
- expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN');
- } else {
- // Not going to bother testing every possible combination.
- }
- });
-
- // @gate !disableStringRefs
- it('should steal the ref if a new string ref is specified without an owner', async () => {
- // Regression test for this specific feature combination calling cloneElement on an element
- // without an owner
- await expect(async () => {
- // create an element without an owner
- const element = React.createElement('div', {id: 'some-id'});
- class Parent extends React.Component {
- render() {
- return {element};
- }
- }
- let child;
- class Child extends React.Component {
- render() {
- child = this;
- const clone = React.cloneElement(this.props.children, {
- ref: 'xyz',
- });
- return {clone}
;
- }
- }
-
- const root = ReactDOMClient.createRoot(document.createElement('div'));
- await act(() => root.render());
- expect(child.refs.xyz.tagName).toBe('DIV');
- }).toErrorDev([
- 'Component "Child" contains the string ref "xyz". Support for ' +
- 'string refs will be removed in a future major release. We recommend ' +
- 'using useRef() or createRef() instead. Learn more about using refs ' +
- 'safely here: https://react.dev/link/strict-mode-string-ref',
- ]);
+ expect(component.childRef).toEqual({current: null});
+ expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN');
});
it('should overwrite props', async () => {
@@ -403,23 +362,12 @@ describe('ReactElementClone', () => {
const clone = React.cloneElement(element, props);
expect(clone.type).toBe(ComponentClass);
expect(clone.key).toBe('12');
- if (gate(flags => flags.disableStringRefs)) {
- expect(clone.props.ref).toBe('34');
- expect(() => expect(clone.ref).toBe('34')).toErrorDev(
- 'Accessing element.ref was removed in React 19',
- {withoutStack: true},
- );
- expect(clone.props).toEqual({foo: 'ef', ref: '34'});
- } else if (gate(flags => !flags.disableStringRefs)) {
- expect(() => {
- expect(clone.ref).toBe(element.ref);
- }).toErrorDev('Accessing element.ref was removed in React 19', {
- withoutStack: true,
- });
- expect(clone.props).toEqual({foo: 'ef', ref: element.ref});
- } else {
- // Not going to bother testing every possible combination.
- }
+ expect(clone.props.ref).toBe('34');
+ expect(() => expect(clone.ref).toBe('34')).toErrorDev(
+ 'Accessing element.ref was removed in React 19',
+ {withoutStack: true},
+ );
+ expect(clone.props).toEqual({foo: 'ef', ref: '34'});
if (__DEV__) {
expect(Object.isFrozen(element)).toBe(true);
expect(Object.isFrozen(element.props)).toBe(true);
diff --git a/packages/react/src/__tests__/ReactStrictMode-test.js b/packages/react/src/__tests__/ReactStrictMode-test.js
index 2ab9c3fa18c9..97fcc1ec8c4c 100644
--- a/packages/react/src/__tests__/ReactStrictMode-test.js
+++ b/packages/react/src/__tests__/ReactStrictMode-test.js
@@ -956,55 +956,6 @@ describe('symbol checks', () => {
});
});
-describe('string refs', () => {
- beforeEach(() => {
- jest.resetModules();
- React = require('react');
- ReactDOM = require('react-dom');
- ReactDOMClient = require('react-dom/client');
- act = require('internal-test-utils').act;
- });
-
- // @gate !disableStringRefs
- it('should warn within a strict tree', async () => {
- const {StrictMode} = React;
-
- class OuterComponent extends React.Component {
- render() {
- return (
-
-
-
- );
- }
- }
-
- class InnerComponent extends React.Component {
- render() {
- return null;
- }
- }
-
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
- await expect(async () => {
- await act(() => {
- root.render();
- });
- }).toErrorDev(
- 'Component "OuterComponent" contains the string ref "somestring". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in InnerComponent (at **)',
- );
-
- await act(() => {
- root.render();
- });
- });
-});
-
describe('context legacy', () => {
beforeEach(() => {
jest.resetModules();
diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts
index 4f4564d356a8..00e3a8b3ff8a 100644
--- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts
+++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts
@@ -697,20 +697,4 @@ describe('ReactTypeScriptClass', function() {
] );
});
}
-
- if (!ReactFeatureFlags.disableStringRefs) {
- it('supports string refs', function() {
- const ref = React.createRef();
- expect(() => {
- test(React.createElement(ClassicRefs, {ref: ref}), 'DIV', 'foo');
- }).toErrorDev([
- 'Component "ClassicRefs" contains the string ref "inner". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'We recommend using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' +
- ' in Inner (at **)',
- ]);
- expect(ref.current.refs.inner.getName()).toBe('foo');
- });
- }
});
diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js
index 3722638ad951..e0a689ec2404 100644
--- a/packages/react/src/jsx/ReactJSXElement.js
+++ b/packages/react/src/jsx/ReactJSXElement.js
@@ -20,13 +20,9 @@ import isValidElementType from 'shared/isValidElementType';
import isArray from 'shared/isArray';
import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
import {
- disableStringRefs,
disableDefaultPropsExceptForClasses,
enableOwnerStacks,
} from 'shared/ReactFeatureFlags';
-import {checkPropStringCoercion} from 'shared/CheckStringCoercion';
-import {ClassComponent} from 'react-reconciler/src/ReactWorkTags';
-import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference');
@@ -59,7 +55,7 @@ function getTaskName(type) {
}
function getOwner() {
- if (__DEV__ || !disableStringRefs) {
+ if (__DEV__) {
const dispatcher = ReactSharedInternals.A;
if (dispatcher === null) {
return null;
@@ -70,17 +66,13 @@ function getOwner() {
}
let specialPropKeyWarningShown;
-let didWarnAboutStringRefs;
let didWarnAboutElementRef;
let didWarnAboutOldJSXRuntime;
if (__DEV__) {
- didWarnAboutStringRefs = {};
didWarnAboutElementRef = {};
}
-const enableFastJSXWithoutStringRefs = disableStringRefs;
-
function hasValidRef(config) {
if (__DEV__) {
if (hasOwnProperty.call(config, 'ref')) {
@@ -105,35 +97,6 @@ function hasValidKey(config) {
return config.key !== undefined;
}
-function warnIfStringRefCannotBeAutoConverted(config, self) {
- if (__DEV__) {
- let owner;
- if (
- !disableStringRefs &&
- typeof config.ref === 'string' &&
- (owner = getOwner()) &&
- self &&
- owner.stateNode !== self
- ) {
- const componentName = getComponentNameFromType(owner.type);
-
- if (!didWarnAboutStringRefs[componentName]) {
- console.error(
- 'Component "%s" contains the string ref "%s". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'This case cannot be automatically converted to an arrow function. ' +
- 'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: ' +
- 'https://react.dev/link/strict-mode-string-ref',
- getComponentNameFromType(owner.type),
- config.ref,
- );
- didWarnAboutStringRefs[componentName] = true;
- }
- }
- }
-}
-
function defineKeyPropWarningGetter(props, displayName) {
if (__DEV__) {
const warnAboutAccessingKey = function () {
@@ -259,22 +222,8 @@ function ReactElement(
value: null,
});
}
- } else if (!__DEV__ && disableStringRefs) {
- // In prod, `ref` is a regular property and _owner doesn't exist.
- element = {
- // This tag allows us to uniquely identify this as a React Element
- $$typeof: REACT_ELEMENT_TYPE,
-
- // Built-in properties that belong on the element
- type,
- key,
- ref,
-
- props,
- };
} else {
- // In prod, `ref` is a regular property. It will be removed in a
- // future release.
+ // In prod, `ref` is a regular property and _owner doesn't exist.
element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
@@ -285,9 +234,6 @@ function ReactElement(
ref,
props,
-
- // Record the component responsible for creating this element.
- _owner: owner,
};
}
@@ -368,10 +314,7 @@ export function jsxProd(type, config, maybeKey) {
}
let props;
- if (
- (enableFastJSXWithoutStringRefs || !('ref' in config)) &&
- !('key' in config)
- ) {
+ if (!('key' in config)) {
// If key was not spread in, we can reuse the original props object. This
// only works for `jsx`, not `createElement`, because `jsx` is a compiler
// target and the compiler always passes a new object. For `createElement`,
@@ -390,11 +333,7 @@ export function jsxProd(type, config, maybeKey) {
for (const propName in config) {
// Skip over reserved prop names
if (propName !== 'key') {
- if (!disableStringRefs && propName === 'ref') {
- props.ref = coerceStringRef(config[propName], getOwner(), type);
- } else {
- props[propName] = config[propName];
- }
+ props[propName] = config[propName];
}
}
}
@@ -637,17 +576,8 @@ function jsxDEVImpl(
key = '' + config.key;
}
- if (!disableStringRefs) {
- if (hasValidRef(config)) {
- warnIfStringRefCannotBeAutoConverted(config, self);
- }
- }
-
let props;
- if (
- (enableFastJSXWithoutStringRefs || !('ref' in config)) &&
- !('key' in config)
- ) {
+ if (!('key' in config)) {
// If key was not spread in, we can reuse the original props object. This
// only works for `jsx`, not `createElement`, because `jsx` is a compiler
// target and the compiler always passes a new object. For `createElement`,
@@ -666,11 +596,7 @@ function jsxDEVImpl(
for (const propName in config) {
// Skip over reserved prop names
if (propName !== 'key') {
- if (!disableStringRefs && propName === 'ref') {
- props.ref = coerceStringRef(config[propName], getOwner(), type);
- } else {
- props[propName] = config[propName];
- }
+ props[propName] = config[propName];
}
}
}
@@ -800,11 +726,6 @@ export function createElement(type, config, children) {
}
}
- if (__DEV__ && !disableStringRefs) {
- if (hasValidRef(config)) {
- warnIfStringRefCannotBeAutoConverted(config, config.__self);
- }
- }
if (hasValidKey(config)) {
if (__DEV__) {
checkKeyStringCoercion(config.key);
@@ -825,11 +746,7 @@ export function createElement(type, config, children) {
propName !== '__self' &&
propName !== '__source'
) {
- if (!disableStringRefs && propName === 'ref') {
- props.ref = coerceStringRef(config[propName], getOwner(), type);
- } else {
- props[propName] = config[propName];
- }
+ props[propName] = config[propName];
}
}
}
@@ -889,7 +806,7 @@ export function cloneAndReplaceKey(oldElement, newKey) {
newKey,
undefined,
undefined,
- !__DEV__ && disableStringRefs ? undefined : oldElement._owner,
+ !__DEV__ ? undefined : oldElement._owner,
oldElement.props,
__DEV__ && enableOwnerStacks ? oldElement._debugStack : undefined,
__DEV__ && enableOwnerStacks ? oldElement._debugTask : undefined,
@@ -921,11 +838,11 @@ export function cloneElement(element, config, children) {
let key = element.key;
// Owner will be preserved, unless ref is overridden
- let owner = !__DEV__ && disableStringRefs ? undefined : element._owner;
+ let owner = !__DEV__ ? undefined : element._owner;
if (config != null) {
if (hasValidRef(config)) {
- owner = __DEV__ || !disableStringRefs ? getOwner() : undefined;
+ owner = __DEV__ ? getOwner() : undefined;
}
if (hasValidKey(config)) {
if (__DEV__) {
@@ -969,11 +886,7 @@ export function cloneElement(element, config, children) {
// Resolve default props
props[propName] = defaultProps[propName];
} else {
- if (!disableStringRefs && propName === 'ref') {
- props.ref = coerceStringRef(config[propName], owner, element.type);
- } else {
- props[propName] = config[propName];
- }
+ props[propName] = config[propName];
}
}
}
@@ -1173,99 +1086,3 @@ function getCurrentComponentErrorInfo(parentType) {
return info;
}
}
-
-function coerceStringRef(mixedRef, owner, type) {
- if (disableStringRefs) {
- return mixedRef;
- }
-
- let stringRef;
- if (typeof mixedRef === 'string') {
- stringRef = mixedRef;
- } else {
- if (typeof mixedRef === 'number' || typeof mixedRef === 'boolean') {
- if (__DEV__) {
- checkPropStringCoercion(mixedRef, 'ref');
- }
- stringRef = '' + mixedRef;
- } else {
- return mixedRef;
- }
- }
-
- const callback = stringRefAsCallbackRef.bind(null, stringRef, type, owner);
- // This is used to check whether two callback refs conceptually represent
- // the same string ref, and can therefore be reused by the reconciler. Needed
- // for backwards compatibility with old Meta code that relies on string refs
- // not being reattached on every render.
- callback.__stringRef = stringRef;
- callback.__type = type;
- callback.__owner = owner;
- return callback;
-}
-
-function stringRefAsCallbackRef(stringRef, type, owner, value) {
- if (disableStringRefs) {
- return;
- }
- if (!owner) {
- throw new Error(
- `Element ref was specified as a string (${stringRef}) but no owner was set. This could happen for one of` +
- ' the following reasons:\n' +
- '1. You may be adding a ref to a function component\n' +
- "2. You may be adding a ref to a component that was not created inside a component's render method\n" +
- '3. You have multiple copies of React loaded\n' +
- 'See https://react.dev/link/refs-must-have-owner for more information.',
- );
- }
- if (owner.tag !== ClassComponent) {
- throw new Error(
- 'Function components cannot have string refs. ' +
- 'We recommend using useRef() instead. ' +
- 'Learn more about using refs safely here: ' +
- 'https://react.dev/link/strict-mode-string-ref',
- );
- }
-
- if (__DEV__) {
- if (
- // Will already warn with "Function components cannot be given refs"
- !(typeof type === 'function' && !isReactClass(type))
- ) {
- const componentName = getComponentNameFromFiber(owner) || 'Component';
- if (!didWarnAboutStringRefs[componentName]) {
- if (__DEV__) {
- console.error(
- 'Component "%s" contains the string ref "%s". Support for string refs ' +
- 'will be removed in a future major release. We recommend using ' +
- 'useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: ' +
- 'https://react.dev/link/strict-mode-string-ref',
- componentName,
- stringRef,
- );
- }
- didWarnAboutStringRefs[componentName] = true;
- }
- }
- }
-
- const inst = owner.stateNode;
- if (!inst) {
- throw new Error(
- `Missing owner for string ref ${stringRef}. This error is likely caused by a ` +
- 'bug in React. Please file an issue.',
- );
- }
-
- const refs = inst.refs;
- if (value === null) {
- delete refs[stringRef];
- } else {
- refs[stringRef] = value;
- }
-}
-
-function isReactClass(type) {
- return type.prototype && type.prototype.isReactComponent;
-}
diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js
index d1159e60373c..44d6e8629db8 100644
--- a/packages/shared/ReactFeatureFlags.js
+++ b/packages/shared/ReactFeatureFlags.js
@@ -208,8 +208,6 @@ export const enableFilterEmptyStringAttributesDOM = true;
// Disabled caching behavior of `react/cache` in client runtimes.
export const disableClientCache = true;
-export const disableStringRefs = true;
-
// Warn on any usage of ReactTestRenderer
export const enableReactTestRendererWarning = true;
diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js
index 7e63db5ef45e..a553c275fed8 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-fb.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js
@@ -41,7 +41,6 @@ export const disableLegacyContext = false;
export const disableLegacyContextForFunctionComponents = false;
export const disableLegacyMode = false;
export const disableSchedulerTimeoutInWorkLoop = false;
-export const disableStringRefs = true;
export const disableTextareaChildren = false;
export const enableAsyncActions = true;
export const enableAsyncDebugInfo = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js
index 644b23b46afa..d59e3f9698d4 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-oss.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js
@@ -30,7 +30,6 @@ export const disableLegacyContext = true;
export const disableLegacyContextForFunctionComponents = true;
export const disableLegacyMode = false;
export const disableSchedulerTimeoutInWorkLoop = false;
-export const disableStringRefs = true;
export const disableTextareaChildren = false;
export const enableAsyncActions = true;
export const enableAsyncDebugInfo = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js
index 2946d5efa11b..c27b2d6913dc 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js
@@ -90,7 +90,6 @@ export const enableSiblingPrerendering = false;
// We really need to get rid of this whole module. Any test renderer specific
// flags should be handled by the Fiber config.
// const __NEXT_MAJOR__ = __EXPERIMENTAL__;
-export const disableStringRefs = true;
export const disableLegacyMode = true;
export const disableLegacyContext = true;
export const disableLegacyContextForFunctionComponents = true;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js
index 1d505aaf56b9..170145c93db6 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js
@@ -22,7 +22,6 @@ export const disableLegacyContext = false;
export const disableLegacyContextForFunctionComponents = false;
export const disableLegacyMode = false;
export const disableSchedulerTimeoutInWorkLoop = false;
-export const disableStringRefs = true;
export const disableTextareaChildren = false;
export const enableAsyncActions = true;
export const enableAsyncDebugInfo = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
index 8e9e8f0ca2d5..46e939fd7319 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
@@ -82,8 +82,6 @@ export const disableClientCache = true;
export const enableServerComponentLogs = true;
export const enableInfiniteRenderLoopDetection = false;
-export const disableStringRefs = true;
-
export const enableReactTestRendererWarning = false;
export const disableLegacyMode = true;
diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js
index dac110129ef5..32a39121441b 100644
--- a/packages/shared/forks/ReactFeatureFlags.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.www.js
@@ -52,7 +52,6 @@ export const enableSuspenseAvoidThisFallback = true;
export const enableSuspenseAvoidThisFallbackFizz = false;
export const disableIEWorkarounds = true;
-export const disableStringRefs = true;
export const enableCPUSuspense = true;
export const enableUseMemoCacheHook = true;
export const enableUseEffectEventHook = true;