@@ -15,6 +15,7 @@ import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
1515import type Store from 'react-devtools-shared/src/devtools/store' ;
1616import type { ProfilingDataFrontend } from 'react-devtools-shared/src/devtools/views/Profiler/types' ;
1717import type { ElementType } from 'react-devtools-shared/src/frontend/types' ;
18+ import type { Node as ReactNode } from 'react' ;
1819
1920import { ReactVersion } from '../../../../ReactVersions' ;
2021
@@ -99,6 +100,131 @@ export async function actAsync(
99100 }
100101}
101102
103+ type RenderImplementation = {
104+ render : ( elements : ?ReactNode ) => ( ) => void ,
105+ unmount : ( ) => void ,
106+ createContainer : ( ) => void ,
107+ getContainer : ( ) => ?HTMLElement ,
108+ } ;
109+
110+ export function getLegacyRenderImplementation ( ) : RenderImplementation {
111+ let ReactDOM ;
112+ let container ;
113+ let unmounted = false ;
114+
115+ beforeEach ( ( ) => {
116+ ReactDOM = require ( 'react-dom' ) ;
117+
118+ createContainer ( ) ;
119+ } ) ;
120+
121+ afterEach ( ( ) => {
122+ if ( ! unmounted ) {
123+ unmount ( ) ;
124+ }
125+
126+ ReactDOM = null ;
127+ container = null ;
128+ } ) ;
129+
130+ function render ( elements ) {
131+ withErrorsOrWarningsIgnored (
132+ [ 'ReactDOM.render is no longer supported in React 18' ] ,
133+ ( ) => {
134+ ReactDOM . render ( elements , container ) ;
135+ } ,
136+ ) ;
137+
138+ return unmount ;
139+ }
140+
141+ function unmount ( ) {
142+ unmounted = true ;
143+
144+ ReactDOM . unmountComponentAtNode ( container ) ;
145+ document . body . removeChild ( container ) ;
146+ }
147+
148+ function createContainer ( ) {
149+ unmounted = false ;
150+
151+ container = document . createElement ( 'div' ) ;
152+ document . body . appendChild ( container ) ;
153+ }
154+
155+ function getContainer ( ) {
156+ return container ;
157+ }
158+
159+ return {
160+ render,
161+ unmount,
162+ createContainer,
163+ getContainer,
164+ } ;
165+ }
166+
167+ export function getModernRenderImplementation ( ) : RenderImplementation {
168+ let ReactDOMClient ;
169+ let container ;
170+ let root ;
171+ let unmounted = false ;
172+
173+ beforeEach ( ( ) => {
174+ ReactDOMClient = require ( 'react-dom/client' ) ;
175+
176+ createContainer ( ) ;
177+ } ) ;
178+
179+ afterEach ( ( ) => {
180+ if ( ! unmounted ) {
181+ unmount ( ) ;
182+ }
183+
184+ ReactDOMClient = null ;
185+ container = null ;
186+ root = null ;
187+ } ) ;
188+
189+ function render ( elements ) {
190+ root . render ( elements ) ;
191+
192+ return unmount ;
193+ }
194+
195+ function unmount ( ) {
196+ unmounted = true ;
197+
198+ root . unmount ( ) ;
199+ document . body . removeChild ( container ) ;
200+ }
201+
202+ function createContainer ( ) {
203+ unmounted = false ;
204+
205+ container = document . createElement ( 'div' ) ;
206+ document . body . appendChild ( container ) ;
207+
208+ root = ReactDOMClient . createRoot ( container ) ;
209+ }
210+
211+ function getContainer ( ) {
212+ return container ;
213+ }
214+
215+ return {
216+ render,
217+ unmount,
218+ createContainer,
219+ getContainer,
220+ } ;
221+ }
222+
223+ export const getVersionedRenderImplementation : ( ) => RenderImplementation =
224+ semver . lt ( requestedReactVersion , '18.0.0' )
225+ ? getLegacyRenderImplementation
226+ : getModernRenderImplementation ;
227+
102228export function beforeEachProfiling ( ) : void {
103229 // Mock React's timing information so that test runs are predictable.
104230 jest . mock ( 'scheduler' , ( ) => jest . requireActual ( 'scheduler/unstable_mock' ) ) ;
0 commit comments