@@ -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,123 @@ 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+ const containersToRemove = [ ] ;
114+
115+ beforeEach ( ( ) => {
116+ ReactDOM = require ( 'react-dom' ) ;
117+
118+ createContainer ( ) ;
119+ } ) ;
120+
121+ afterEach ( ( ) => {
122+ containersToRemove . forEach ( c => document . body . removeChild ( c ) ) ;
123+ containersToRemove . splice ( 0 , containersToRemove . length ) ;
124+
125+ ReactDOM = null ;
126+ container = null ;
127+ } ) ;
128+
129+ function render ( elements ) {
130+ withErrorsOrWarningsIgnored (
131+ [ 'ReactDOM.render is no longer supported in React 18' ] ,
132+ ( ) => {
133+ ReactDOM . render ( elements , container ) ;
134+ } ,
135+ ) ;
136+
137+ return unmount ;
138+ }
139+
140+ function unmount ( ) {
141+ ReactDOM . unmountComponentAtNode ( container ) ;
142+ }
143+
144+ function createContainer ( ) {
145+ container = document . createElement ( 'div' ) ;
146+ document . body . appendChild ( container ) ;
147+
148+ containersToRemove . push ( container ) ;
149+ }
150+
151+ function getContainer ( ) {
152+ return container ;
153+ }
154+
155+ return {
156+ render,
157+ unmount,
158+ createContainer,
159+ getContainer,
160+ } ;
161+ }
162+
163+ export function getModernRenderImplementation ( ) : RenderImplementation {
164+ let ReactDOMClient ;
165+ let container ;
166+ let root ;
167+ const containersToRemove = [ ] ;
168+
169+ beforeEach ( ( ) => {
170+ ReactDOMClient = require ( 'react-dom/client' ) ;
171+
172+ createContainer ( ) ;
173+ } ) ;
174+
175+ afterEach ( ( ) => {
176+ containersToRemove . forEach ( c => document . body . removeChild ( c ) ) ;
177+ containersToRemove . splice ( 0 , containersToRemove . length ) ;
178+
179+ ReactDOMClient = null ;
180+ container = null ;
181+ root = null ;
182+ } ) ;
183+
184+ function render ( elements ) {
185+ root . render ( elements ) ;
186+
187+ return unmount ;
188+ }
189+
190+ function unmount ( ) {
191+ root . unmount ( ) ;
192+ }
193+
194+ function createContainer ( ) {
195+ container = document . createElement ( 'div' ) ;
196+ document . body . appendChild ( container ) ;
197+
198+ root = ReactDOMClient . createRoot ( container ) ;
199+
200+ containersToRemove . push ( container ) ;
201+ }
202+
203+ function getContainer ( ) {
204+ return container ;
205+ }
206+
207+ return {
208+ render,
209+ unmount,
210+ createContainer,
211+ getContainer,
212+ } ;
213+ }
214+
215+ export const getVersionedRenderImplementation : ( ) => RenderImplementation =
216+ semver . lt ( requestedReactVersion , '18.0.0' )
217+ ? getLegacyRenderImplementation
218+ : getModernRenderImplementation ;
219+
102220export function beforeEachProfiling ( ) : void {
103221 // Mock React's timing information so that test runs are predictable.
104222 jest . mock ( 'scheduler' , ( ) => jest . requireActual ( 'scheduler/unstable_mock' ) ) ;
0 commit comments