@@ -15,6 +15,7 @@ import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
15
15
import type Store from 'react-devtools-shared/src/devtools/store' ;
16
16
import type { ProfilingDataFrontend } from 'react-devtools-shared/src/devtools/views/Profiler/types' ;
17
17
import type { ElementType } from 'react-devtools-shared/src/frontend/types' ;
18
+ import type { Node as ReactNode } from 'react' ;
18
19
19
20
import { ReactVersion } from '../../../../ReactVersions' ;
20
21
@@ -99,6 +100,131 @@ export async function actAsync(
99
100
}
100
101
}
101
102
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
+
102
228
export function beforeEachProfiling ( ) : void {
103
229
// Mock React's timing information so that test runs are predictable.
104
230
jest . mock ( 'scheduler' , ( ) => jest . requireActual ( 'scheduler/unstable_mock' ) ) ;
0 commit comments