From 9928ca53e4f173d571e34e4eca050df088919511 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Mon, 5 Feb 2024 16:15:40 -0800 Subject: [PATCH] Expose `findDOMNode` on internals Exposes `findDOMNode` on internals and updates tests to read from internals --- packages/react-dom/index.experimental.js | 1 - packages/react-dom/index.js | 1 - packages/react-dom/index.stable.js | 1 - .../react-dom/src/ReactDOMSharedInternals.js | 3 ++ .../__tests__/ReactComponentLifeCycle-test.js | 5 +++- .../react-dom/src/__tests__/ReactDOM-test.js | 5 +++- .../src/__tests__/ReactDOMComponent-test.js | 6 +++- .../__tests__/ReactDOMEventListener-test.js | 12 ++++++-- .../src/__tests__/ReactDOMLegacyFiber-test.js | 30 +++++++++++++++---- .../ReactDOMSuspensePlaceholder-test.js | 11 ++++--- .../src/__tests__/ReactEmptyComponent-test.js | 11 ++++--- .../ReactLegacyCompositeComponent-test.js | 17 ++++++----- .../src/__tests__/ReactLegacyUpdates-test.js | 13 ++++---- .../src/__tests__/ReactUpdates-test.js | 11 ++++--- .../src/__tests__/findDOMNode-test.js | 22 +++++++------- .../react-dom-server-rendering-stub-test.js | 3 ++ packages/react-dom/src/client/ReactDOM.js | 3 ++ .../react-dom/src/client/ReactDOMLegacy.js | 2 ++ .../unstable_testing.experimental.js | 1 - packages/react-dom/unstable_testing.js | 1 - packages/react-dom/unstable_testing.stable.js | 1 - .../ReactCoffeeScriptClass-test.coffee | 6 ---- .../react/src/__tests__/ReactES6Class-test.js | 7 ----- .../src/__tests__/ReactJSXRuntime-test.js | 7 +++-- .../__tests__/ReactTypeScriptClass-test.ts | 7 ----- 25 files changed, 114 insertions(+), 73 deletions(-) diff --git a/packages/react-dom/index.experimental.js b/packages/react-dom/index.experimental.js index 539dbddb5a89f..5090305e9d758 100644 --- a/packages/react-dom/index.experimental.js +++ b/packages/react-dom/index.experimental.js @@ -12,7 +12,6 @@ export { createPortal, createRoot, hydrateRoot, - findDOMNode, flushSync, unstable_batchedUpdates, unstable_runWithPriority, // DO NOT USE: Temporarily exposed to migrate off of Scheduler.runWithPriority. diff --git a/packages/react-dom/index.js b/packages/react-dom/index.js index 0c55c3a92219a..30ccf0a2eac89 100644 --- a/packages/react-dom/index.js +++ b/packages/react-dom/index.js @@ -14,7 +14,6 @@ export { createPortal, createRoot, hydrateRoot, - findDOMNode, flushSync, render, unmountComponentAtNode, diff --git a/packages/react-dom/index.stable.js b/packages/react-dom/index.stable.js index 5e5a5fe275d95..a817a6b3d9af3 100644 --- a/packages/react-dom/index.stable.js +++ b/packages/react-dom/index.stable.js @@ -12,7 +12,6 @@ export { createPortal, createRoot, hydrateRoot, - findDOMNode, flushSync, render, unmountComponentAtNode, diff --git a/packages/react-dom/src/ReactDOMSharedInternals.js b/packages/react-dom/src/ReactDOMSharedInternals.js index 9f721b718b819..6de3648103591 100644 --- a/packages/react-dom/src/ReactDOMSharedInternals.js +++ b/packages/react-dom/src/ReactDOMSharedInternals.js @@ -7,6 +7,7 @@ * @flow */ +import type {FindDOMNodeType} from './client/ReactDOMLegacy.js'; import type {HostDispatcher} from './shared/ReactDOMTypes'; type InternalsType = { @@ -15,6 +16,7 @@ type InternalsType = { ReactDOMCurrentDispatcher: { current: HostDispatcher, }, + findDOMNode: null | FindDOMNodeType, }; function noop() {} @@ -35,6 +37,7 @@ const Internals: InternalsType = ({ ReactDOMCurrentDispatcher: { current: DefaultDispatcher, }, + findDOMNode: null, }: any); export default Internals; diff --git a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js index 9fc7498c10730..d07ab9e71b0b3 100644 --- a/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js +++ b/packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js @@ -15,6 +15,7 @@ let React; let ReactDOM; let ReactDOMClient; let PropTypes; +let findDOMNode; const clone = function (o) { return JSON.parse(JSON.stringify(o)); @@ -95,6 +96,8 @@ describe('ReactComponentLifeCycle', () => { React = require('react'); ReactDOM = require('react-dom'); + findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; ReactDOMClient = require('react-dom/client'); PropTypes = require('prop-types'); }); @@ -383,7 +386,7 @@ describe('ReactComponentLifeCycle', () => { } render() { if (this.state.isMounted) { - expect(ReactDOM.findDOMNode(this).tagName).toBe('DIV'); + expect(findDOMNode(this).tagName).toBe('DIV'); } return
; } diff --git a/packages/react-dom/src/__tests__/ReactDOM-test.js b/packages/react-dom/src/__tests__/ReactDOM-test.js index e72f726c16503..2cb0f24e6944a 100644 --- a/packages/react-dom/src/__tests__/ReactDOM-test.js +++ b/packages/react-dom/src/__tests__/ReactDOM-test.js @@ -11,6 +11,7 @@ let React; let ReactDOM; +let findDOMNode; let ReactDOMClient; let ReactDOMServer; @@ -21,6 +22,8 @@ describe('ReactDOM', () => { jest.resetModules(); React = require('react'); ReactDOM = require('react-dom'); + findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; ReactDOMClient = require('react-dom/client'); ReactDOMServer = require('react-dom/server'); @@ -494,7 +497,7 @@ describe('ReactDOM', () => { }); const App = () => { - ReactDOM.findDOMNode(instance); + findDOMNode(instance); return
; }; diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index 5c62605af2bc4..6ce4ca814f661 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -2121,7 +2121,11 @@ describe('ReactDOMComponent', () => { componentWillUnmount() { // Should not throw - expect(ReactDOM.findDOMNode(this).nodeName).toBe('SPAN'); + expect( + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + this, + ).nodeName, + ).toBe('SPAN'); } } diff --git a/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js b/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js index f059d7bd2f560..189bc1d99f423 100644 --- a/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMEventListener-test.js @@ -114,10 +114,18 @@ describe('ReactDOMEventListener', () => { this.setState({clicked: true}); }; componentDidMount() { - expect(ReactDOM.findDOMNode(this)).toBe(container.firstChild); + expect( + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + this, + ), + ).toBe(container.firstChild); } componentDidUpdate() { - expect(ReactDOM.findDOMNode(this)).toBe(container.firstChild); + expect( + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + this, + ), + ).toBe(container.firstChild); } render() { if (this.state.clicked) { diff --git a/packages/react-dom/src/__tests__/ReactDOMLegacyFiber-test.js b/packages/react-dom/src/__tests__/ReactDOMLegacyFiber-test.js index ed45e850178c1..9725d5fe0fbdc 100644 --- a/packages/react-dom/src/__tests__/ReactDOMLegacyFiber-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMLegacyFiber-test.js @@ -111,7 +111,10 @@ describe('ReactDOMLegacyFiber', () => { container, ); - const textNode = ReactDOM.findDOMNode(instance); + const textNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + instance, + ); expect(textNode).toBe(container.firstChild); expect(textNode.nodeType).toBe(3); expect(textNode.nodeValue).toBe('foo'); @@ -130,7 +133,10 @@ describe('ReactDOMLegacyFiber', () => { expect(container.childNodes.length).toBe(2); - const firstNode = ReactDOM.findDOMNode(instance); + const firstNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + instance, + ); expect(firstNode).toBe(container.firstChild); expect(firstNode.tagName).toBe('DIV'); }); @@ -159,7 +165,10 @@ describe('ReactDOMLegacyFiber', () => { expect(container.childNodes.length).toBe(2); - const firstNode = ReactDOM.findDOMNode(instance); + const firstNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + instance, + ); expect(firstNode).toBe(container.firstChild); expect(firstNode.tagName).toBe('DIV'); }); @@ -183,7 +192,10 @@ describe('ReactDOMLegacyFiber', () => { expect(container.childNodes.length).toBe(2); - const firstNode = ReactDOM.findDOMNode(instance); + const firstNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + instance, + ); expect(firstNode).toBe(container.firstChild); expect(firstNode.tagName).toBe('DIV'); }); @@ -878,13 +890,19 @@ describe('ReactDOMLegacyFiber', () => { } const myNodeA = ReactDOM.render(, container); - const a = ReactDOM.findDOMNode(myNodeA); + const a = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + myNodeA, + ); expect(a.tagName).toBe('DIV'); const myNodeB = ReactDOM.render(, container); expect(myNodeA === myNodeB).toBe(true); - const b = ReactDOM.findDOMNode(myNodeB); + const b = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode( + myNodeB, + ); expect(b.tagName).toBe('SPAN'); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js b/packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js index 089e6329e068b..12916166ecf0a 100644 --- a/packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js @@ -11,6 +11,7 @@ let React; let ReactDOM; +let findDOMNode; let ReactDOMClient; let Suspense; let Scheduler; @@ -24,6 +25,8 @@ describe('ReactDOMSuspensePlaceholder', () => { jest.resetModules(); React = require('react'); ReactDOM = require('react-dom'); + findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; ReactDOMClient = require('react-dom/client'); Scheduler = require('scheduler'); act = require('internal-test-utils').act; @@ -232,11 +235,11 @@ describe('ReactDOMSuspensePlaceholder', () => { class Child extends React.Component { componentDidMount() { log.push('cDM ' + this.props.id); - ReactDOM.findDOMNode(this); + findDOMNode(this); } componentDidUpdate() { log.push('cDU ' + this.props.id); - ReactDOM.findDOMNode(this); + findDOMNode(this); } render() { return 'child'; @@ -291,12 +294,12 @@ describe('ReactDOMSuspensePlaceholder', () => { class Child extends React.Component { componentDidMount() { log.push('cDM'); - ReactDOM.findDOMNode(this); + findDOMNode(this); } componentDidUpdate() { log.push('cDU'); - ReactDOM.findDOMNode(this); + findDOMNode(this); } render() { diff --git a/packages/react-dom/src/__tests__/ReactEmptyComponent-test.js b/packages/react-dom/src/__tests__/ReactEmptyComponent-test.js index 9316ad4392f61..d5274f964c2b5 100644 --- a/packages/react-dom/src/__tests__/ReactEmptyComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactEmptyComponent-test.js @@ -11,6 +11,7 @@ let React; let ReactDOM; +let findDOMNode; let ReactDOMClient; let TogglingComponent; let act; @@ -25,6 +26,8 @@ describe('ReactEmptyComponent', () => { React = require('react'); ReactDOM = require('react-dom'); + findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; ReactDOMClient = require('react-dom/client'); Scheduler = require('scheduler'); const InternalTestUtils = require('internal-test-utils'); @@ -37,12 +40,12 @@ describe('ReactEmptyComponent', () => { state = {component: this.props.firstComponent}; componentDidMount() { - Scheduler.log('mount ' + ReactDOM.findDOMNode(this)?.nodeName); + Scheduler.log('mount ' + findDOMNode(this)?.nodeName); this.setState({component: this.props.secondComponent}); } componentDidUpdate() { - Scheduler.log('update ' + ReactDOM.findDOMNode(this)?.nodeName); + Scheduler.log('update ' + findDOMNode(this)?.nodeName); } render() { @@ -244,13 +247,13 @@ describe('ReactEmptyComponent', () => { componentDidMount() { // Make sure the DOM node resolves properly even if we're replacing a // `null` component - expect(ReactDOM.findDOMNode(this)).not.toBe(null); + expect(findDOMNode(this)).not.toBe(null); } componentWillUnmount() { // Even though we're getting replaced by `null`, we haven't been // replaced yet! - expect(ReactDOM.findDOMNode(this)).not.toBe(null); + expect(findDOMNode(this)).not.toBe(null); } } diff --git a/packages/react-dom/src/__tests__/ReactLegacyCompositeComponent-test.js b/packages/react-dom/src/__tests__/ReactLegacyCompositeComponent-test.js index 974403acc4197..1f62d9ab20d97 100644 --- a/packages/react-dom/src/__tests__/ReactLegacyCompositeComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactLegacyCompositeComponent-test.js @@ -11,6 +11,7 @@ let React; let ReactDOM; +let findDOMNode; let ReactDOMClient; let PropTypes; let act; @@ -20,6 +21,8 @@ describe('ReactLegacyCompositeComponent', () => { jest.resetModules(); React = require('react'); ReactDOM = require('react-dom'); + findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; ReactDOMClient = require('react-dom/client'); PropTypes = require('prop-types'); act = require('internal-test-utils').act; @@ -115,7 +118,7 @@ describe('ReactLegacyCompositeComponent', () => { await act(() => { root.render( (component = current)} />); }); - expect(ReactDOM.findDOMNode(component).innerHTML).toBe('bar'); + expect(findDOMNode(component).innerHTML).toBe('bar'); }); // @gate !disableLegacyContext @@ -661,14 +664,14 @@ describe('ReactLegacyCompositeComponent', () => { const container = document.createElement('div'); const comp = ReactDOM.render(, container); - expect(ReactDOM.findDOMNode(comp.static0Ref.current).textContent).toBe('A'); - expect(ReactDOM.findDOMNode(comp.static1Ref.current).textContent).toBe('B'); + expect(findDOMNode(comp.static0Ref.current).textContent).toBe('A'); + expect(findDOMNode(comp.static1Ref.current).textContent).toBe('B'); // When flipping the order, the refs should update even though the actual // contents do not ReactDOM.render(, container); - expect(ReactDOM.findDOMNode(comp.static0Ref.current).textContent).toBe('B'); - expect(ReactDOM.findDOMNode(comp.static1Ref.current).textContent).toBe('A'); + expect(findDOMNode(comp.static0Ref.current).textContent).toBe('B'); + expect(findDOMNode(comp.static1Ref.current).textContent).toBe('A'); }); // @gate !disableLegacyMode @@ -678,12 +681,12 @@ describe('ReactLegacyCompositeComponent', () => { class Component extends React.Component { componentDidMount() { - a = ReactDOM.findDOMNode(this); + a = findDOMNode(this); expect(a).not.toBe(null); } componentWillUnmount() { - b = ReactDOM.findDOMNode(this); + b = findDOMNode(this); expect(b).not.toBe(null); } diff --git a/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js b/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js index 1346d2f260b46..68d9edf05b6bd 100644 --- a/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js @@ -11,6 +11,7 @@ let React; let ReactDOM; +let findDOMNode; let act; let Scheduler; let assertLog; @@ -22,6 +23,8 @@ describe('ReactLegacyUpdates', () => { jest.resetModules(); React = require('react'); ReactDOM = require('react-dom'); + findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; act = require('internal-test-utils').act; Scheduler = require('scheduler'); @@ -561,7 +564,7 @@ describe('ReactLegacyUpdates', () => { state = {x: 0}; componentDidUpdate() { - expect(ReactDOM.findDOMNode(b).textContent).toBe('B1'); + expect(findDOMNode(b).textContent).toBe('B1'); aUpdated = true; } @@ -699,7 +702,7 @@ describe('ReactLegacyUpdates', () => { depth={this.props.depth + 1} count={this.props.count} />, - ReactDOM.findDOMNode(this), + findDOMNode(this), ); } } @@ -770,10 +773,10 @@ describe('ReactLegacyUpdates', () => { const x = ReactDOM.render(, container); container = document.createElement('div'); const y = ReactDOM.render(, container); - expect(ReactDOM.findDOMNode(x).textContent).toBe('0'); + expect(findDOMNode(x).textContent).toBe('0'); y.forceUpdate(); - expect(ReactDOM.findDOMNode(x).textContent).toBe('1'); + expect(findDOMNode(x).textContent).toBe('1'); }); // @gate !disableLegacyMode @@ -816,7 +819,7 @@ describe('ReactLegacyUpdates', () => { }); expect(a.state.x).toBe(1); - expect(ReactDOM.findDOMNode(a).textContent).toBe('A1'); + expect(findDOMNode(a).textContent).toBe('A1'); }); // @gate !disableLegacyMode diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index 82d1955c0e5bf..d4acfaa9b35f8 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -11,6 +11,7 @@ let React; let ReactDOM; +let findDOMNode; let ReactDOMClient; let act; let Scheduler; @@ -23,6 +24,8 @@ describe('ReactUpdates', () => { jest.resetModules(); React = require('react'); ReactDOM = require('react-dom'); + findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; ReactDOMClient = require('react-dom/client'); act = require('internal-test-utils').act; Scheduler = require('scheduler'); @@ -659,7 +662,7 @@ describe('ReactUpdates', () => { a = this; } componentDidUpdate() { - expect(ReactDOM.findDOMNode(b).textContent).toBe('B1'); + expect(findDOMNode(b).textContent).toBe('B1'); aUpdated = true; } @@ -801,7 +804,7 @@ describe('ReactUpdates', () => { componentDidMount() { instances.push(this); if (this.props.depth < this.props.count) { - const root = ReactDOMClient.createRoot(ReactDOM.findDOMNode(this)); + const root = ReactDOMClient.createRoot(findDOMNode(this)); root.render( { root.render( (y = current)} />); }); - expect(ReactDOM.findDOMNode(x).textContent).toBe('0'); + expect(findDOMNode(x).textContent).toBe('0'); await act(() => { y.forceUpdate(); }); - expect(ReactDOM.findDOMNode(x).textContent).toBe('1'); + expect(findDOMNode(x).textContent).toBe('1'); }); it('should queue updates from during mount', async () => { diff --git a/packages/react-dom/src/__tests__/findDOMNode-test.js b/packages/react-dom/src/__tests__/findDOMNode-test.js index a67316a97b003..6dfcae82d4cfa 100644 --- a/packages/react-dom/src/__tests__/findDOMNode-test.js +++ b/packages/react-dom/src/__tests__/findDOMNode-test.js @@ -11,11 +11,13 @@ const React = require('react'); const ReactDOM = require('react-dom'); +const findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; const StrictMode = React.StrictMode; describe('findDOMNode', () => { it('findDOMNode should return null if passed null', () => { - expect(ReactDOM.findDOMNode(null)).toBe(null); + expect(findDOMNode(null)).toBe(null); }); // @gate !disableLegacyMode @@ -32,8 +34,8 @@ describe('findDOMNode', () => { const container = document.createElement('div'); const myNode = ReactDOM.render(, container); - const myDiv = ReactDOM.findDOMNode(myNode); - const mySameDiv = ReactDOM.findDOMNode(myDiv); + const myDiv = findDOMNode(myNode); + const mySameDiv = findDOMNode(myDiv); expect(myDiv.tagName).toBe('DIV'); expect(mySameDiv).toBe(myDiv); }); @@ -55,19 +57,19 @@ describe('findDOMNode', () => { const container = document.createElement('div'); const myNodeA = ReactDOM.render(, container); - const a = ReactDOM.findDOMNode(myNodeA); + const a = findDOMNode(myNodeA); expect(a).toBe(null); const myNodeB = ReactDOM.render(, container); expect(myNodeA === myNodeB).toBe(true); - const b = ReactDOM.findDOMNode(myNodeB); + const b = findDOMNode(myNodeB); expect(b.tagName).toBe('SPAN'); }); it('findDOMNode should reject random objects', () => { expect(function () { - ReactDOM.findDOMNode({foo: 'bar'}); + findDOMNode({foo: 'bar'}); }).toThrowError('Argument appears to not be a ReactComponent. Keys: foo'); }); @@ -83,7 +85,7 @@ describe('findDOMNode', () => { const inst = ReactDOM.render(, container); ReactDOM.unmountComponentAtNode(container); - expect(() => ReactDOM.findDOMNode(inst)).toThrowError( + expect(() => findDOMNode(inst)).toThrowError( 'Unable to find node on an unmounted component.', ); }); @@ -92,7 +94,7 @@ describe('findDOMNode', () => { it('findDOMNode should not throw an error when called within a component that is not mounted', () => { class Bar extends React.Component { UNSAFE_componentWillMount() { - expect(ReactDOM.findDOMNode(this)).toBeNull(); + expect(findDOMNode(this)).toBeNull(); } render() { @@ -127,7 +129,7 @@ describe('findDOMNode', () => { ); let match; - expect(() => (match = ReactDOM.findDOMNode(parent))).toErrorDev([ + expect(() => (match = findDOMNode(parent))).toErrorDev([ 'Warning: findDOMNode is deprecated in StrictMode. ' + 'findDOMNode was passed an instance of ContainsStrictModeChild which renders StrictMode children. ' + 'Instead, add a ref directly to the element you want to reference. ' + @@ -160,7 +162,7 @@ describe('findDOMNode', () => { ); let match; - expect(() => (match = ReactDOM.findDOMNode(parent))).toErrorDev([ + expect(() => (match = findDOMNode(parent))).toErrorDev([ 'Warning: findDOMNode is deprecated in StrictMode. ' + 'findDOMNode was passed an instance of IsInStrictMode which is inside StrictMode. ' + 'Instead, add a ref directly to the element you want to reference. ' + diff --git a/packages/react-dom/src/__tests__/react-dom-server-rendering-stub-test.js b/packages/react-dom/src/__tests__/react-dom-server-rendering-stub-test.js index 997f87fa309cd..28c4cb536d77d 100644 --- a/packages/react-dom/src/__tests__/react-dom-server-rendering-stub-test.js +++ b/packages/react-dom/src/__tests__/react-dom-server-rendering-stub-test.js @@ -30,6 +30,9 @@ describe('react-dom-server-rendering-stub', () => { expect(ReactDOM.createRoot).toBe(undefined); expect(ReactDOM.hydrateRoot).toBe(undefined); expect(ReactDOM.findDOMNode).toBe(undefined); + expect( + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode, + ).toBe(null); expect(ReactDOM.hydrate).toBe(undefined); expect(ReactDOM.render).toBe(undefined); expect(ReactDOM.unmountComponentAtNode).toBe(undefined); diff --git a/packages/react-dom/src/client/ReactDOM.js b/packages/react-dom/src/client/ReactDOM.js index 9f9ea849fd66d..5f48120f1f68e 100644 --- a/packages/react-dom/src/client/ReactDOM.js +++ b/packages/react-dom/src/client/ReactDOM.js @@ -164,6 +164,9 @@ function flushSync(fn: (() => R) | void): R | void { return flushSyncWithoutWarningIfAlreadyRendering(fn); } +// Expose findDOMNode on internals +Internals.findDOMNode = findDOMNode; + export { createPortal, batchedUpdates as unstable_batchedUpdates, diff --git a/packages/react-dom/src/client/ReactDOMLegacy.js b/packages/react-dom/src/client/ReactDOMLegacy.js index cd651488eb68c..46220501a5e1e 100644 --- a/packages/react-dom/src/client/ReactDOMLegacy.js +++ b/packages/react-dom/src/client/ReactDOMLegacy.js @@ -234,6 +234,8 @@ function legacyRenderSubtreeIntoContainer( return getPublicRootInstance(root); } +export type FindDOMNodeType = typeof findDOMNode; + export function findDOMNode( componentOrElement: Element | ?React$Component, ): null | Element | Text { diff --git a/packages/react-dom/unstable_testing.experimental.js b/packages/react-dom/unstable_testing.experimental.js index a7b01b449639c..2cbd3557cca93 100644 --- a/packages/react-dom/unstable_testing.experimental.js +++ b/packages/react-dom/unstable_testing.experimental.js @@ -9,7 +9,6 @@ export { createPortal, - findDOMNode, flushSync, unstable_batchedUpdates, useFormStatus, diff --git a/packages/react-dom/unstable_testing.js b/packages/react-dom/unstable_testing.js index 080b7340d11b2..1e973748c7cb8 100644 --- a/packages/react-dom/unstable_testing.js +++ b/packages/react-dom/unstable_testing.js @@ -9,7 +9,6 @@ export { createPortal, - findDOMNode, flushSync, render, unmountComponentAtNode, diff --git a/packages/react-dom/unstable_testing.stable.js b/packages/react-dom/unstable_testing.stable.js index 855f6f1fc006a..0b47d34c0acb0 100644 --- a/packages/react-dom/unstable_testing.stable.js +++ b/packages/react-dom/unstable_testing.stable.js @@ -9,7 +9,6 @@ export { createPortal, - findDOMNode, flushSync, render, unmountComponentAtNode, diff --git a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee index d4b9e0bea284f..f29f38a128b34 100644 --- a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee @@ -562,10 +562,4 @@ describe 'ReactCoffeeScriptClass', -> ]); expect(ref.current.refs.inner.getName()).toBe 'foo' - it 'supports drilling through to the DOM using findDOMNode', -> - ref = React.createRef() - test React.createElement(InnerComponent, name: 'foo', ref: ref), 'DIV', 'foo' - node = ReactDOM.findDOMNode(ref.current) - expect(node).toBe container.firstChild - undefined diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js index fbd7ef13df685..de9eab6399f9c 100644 --- a/packages/react/src/__tests__/ReactES6Class-test.js +++ b/packages/react/src/__tests__/ReactES6Class-test.js @@ -607,11 +607,4 @@ describe('ReactES6Class', () => { expect(ref.current.refs.inner.getName()).toBe('foo'); }); } - - it('supports drilling through to the DOM using findDOMNode', () => { - const ref = React.createRef(); - test(, 'DIV', 'foo'); - const node = ReactDOM.findDOMNode(ref.current); - expect(node).toBe(container.firstChild); - }); }); diff --git a/packages/react/src/__tests__/ReactJSXRuntime-test.js b/packages/react/src/__tests__/ReactJSXRuntime-test.js index 3f1042435523a..db488e1684001 100644 --- a/packages/react/src/__tests__/ReactJSXRuntime-test.js +++ b/packages/react/src/__tests__/ReactJSXRuntime-test.js @@ -15,6 +15,7 @@ let ReactDOMClient; let JSXRuntime; let JSXDEVRuntime; let act; +let findDOMNode; // NOTE: Prefer to call the JSXRuntime directly in these tests so we can be // certain that we are testing the runtime behavior, as opposed to the Babel @@ -29,6 +30,8 @@ describe('ReactJSXRuntime', () => { ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); act = require('internal-test-utils').act; + findDOMNode = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findDOMNode; }); it('allows static methods to be called using the type property', () => { @@ -130,9 +133,9 @@ describe('ReactJSXRuntime', () => { const outer = container.firstChild; if (__DEV__) { - expect(ReactDOM.findDOMNode(outer).className).toBe('moo'); + expect(findDOMNode(outer).className).toBe('moo'); } else { - expect(ReactDOM.findDOMNode(outer).className).toBe('quack'); + expect(findDOMNode(outer).className).toBe('quack'); } }); diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts index 8d39b9d7c1b02..fa59b6ce644e5 100644 --- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts +++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts @@ -709,11 +709,4 @@ describe('ReactTypeScriptClass', function() { expect(ref.current.refs.inner.getName()).toBe('foo'); }); } - - it('supports drilling through to the DOM using findDOMNode', function() { - const ref = React.createRef(); - test(React.createElement(Inner, {name: 'foo', ref: ref}), 'DIV', 'foo'); - const node = ReactDOM.findDOMNode(ref.current); - expect(node).toBe(container.firstChild); - }); });