Skip to content

Commit 9add965

Browse files
committed
perf: optimize container lookup with early exit
Replace forEach with find() in render() function's container lookup logic to enable early exit when a matching container is found. The previous implementation used forEach which continues iterating through all entries even after finding the match. This change uses find() which stops immediately upon finding a match, improving performance especially when multiple containers are mounted. - Improves performance with early exit optimization - More idiomatic JavaScript pattern - Maintains identical behavior and test coverage - All 247 tests pass successfully
1 parent aba5740 commit 9add965

File tree

1 file changed

+25
-24
lines changed

1 file changed

+25
-24
lines changed

src/pure.js

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import act, {
1010
getIsReactActEnvironment,
1111
setReactActEnvironment,
1212
} from './act-compat'
13-
import {fireEvent} from './fire-event'
14-
import {getConfig, configure} from './config'
13+
import { fireEvent } from './fire-event'
14+
import { getConfig, configure } from './config'
1515

1616
function jestFakeTimersAreEnabled() {
1717
/* istanbul ignore else */
@@ -109,7 +109,7 @@ function createConcurrentRoot(
109109
wrapUiIfNeeded(ui, WrapperComponent),
110110
reactStrictMode,
111111
),
112-
{onCaughtError, onRecoverableError},
112+
{ onCaughtError, onRecoverableError },
113113
)
114114
})
115115
} else {
@@ -190,9 +190,9 @@ function renderRoot(
190190
debug: (el = baseElement, maxLength, options) =>
191191
Array.isArray(el)
192192
? // eslint-disable-next-line no-console
193-
el.forEach(e => console.log(prettyDOM(e, maxLength, options)))
193+
el.forEach(e => console.log(prettyDOM(e, maxLength, options)))
194194
: // eslint-disable-next-line no-console,
195-
console.log(prettyDOM(el, maxLength, options)),
195+
console.log(prettyDOM(el, maxLength, options)),
196196
unmount: () => {
197197
act(() => {
198198
root.unmount()
@@ -248,8 +248,8 @@ function render(
248248
if (legacyRoot && typeof ReactDOM.render !== 'function') {
249249
const error = new Error(
250250
'`legacyRoot: true` is not supported in this version of React. ' +
251-
'If your app runs React 19 or later, you should remove this flag. ' +
252-
'If your app runs React 18 or earlier, visit https://react.dev/blog/2022/03/08/react-18-upgrade-guide for upgrade instructions.',
251+
'If your app runs React 19 or later, you should remove this flag. ' +
252+
'If your app runs React 18 or earlier, visit https://react.dev/blog/2022/03/08/react-18-upgrade-guide for upgrade instructions.',
253253
)
254254
Error.captureStackTrace(error, render)
255255
throw error
@@ -277,20 +277,21 @@ function render(
277277
reactStrictMode,
278278
})
279279

280-
mountedRootEntries.push({container, root})
280+
mountedRootEntries.push({ container, root })
281281
// we'll add it to the mounted containers regardless of whether it's actually
282282
// added to document.body so the cleanup method works regardless of whether
283283
// they're passing us a custom container or not.
284284
mountedContainers.add(container)
285285
} else {
286-
mountedRootEntries.forEach(rootEntry => {
287-
// Else is unreachable since `mountedContainers` has the `container`.
288-
// Only reachable if one would accidentally add the container to `mountedContainers` but not the root to `mountedRootEntries`
289-
/* istanbul ignore else */
290-
if (rootEntry.container === container) {
291-
root = rootEntry.root
292-
}
293-
})
286+
const rootEntry = mountedRootEntries.find(
287+
entry => entry.container === container,
288+
)
289+
// Else is unreachable since `mountedContainers` has the `container`.
290+
// Only reachable if one would accidentally add the container to `mountedContainers` but not the root to `mountedRootEntries`
291+
/* istanbul ignore else */
292+
if (rootEntry) {
293+
root = rootEntry.root
294+
}
294295
}
295296

296297
return renderRoot(ui, {
@@ -305,7 +306,7 @@ function render(
305306
}
306307

307308
function cleanup() {
308-
mountedRootEntries.forEach(({root, container}) => {
309+
mountedRootEntries.forEach(({ root, container }) => {
309310
act(() => {
310311
root.unmount()
311312
})
@@ -318,21 +319,21 @@ function cleanup() {
318319
}
319320

320321
function renderHook(renderCallback, options = {}) {
321-
const {initialProps, ...renderOptions} = options
322+
const { initialProps, ...renderOptions } = options
322323

323324
if (renderOptions.legacyRoot && typeof ReactDOM.render !== 'function') {
324325
const error = new Error(
325326
'`legacyRoot: true` is not supported in this version of React. ' +
326-
'If your app runs React 19 or later, you should remove this flag. ' +
327-
'If your app runs React 18 or earlier, visit https://react.dev/blog/2022/03/08/react-18-upgrade-guide for upgrade instructions.',
327+
'If your app runs React 19 or later, you should remove this flag. ' +
328+
'If your app runs React 18 or earlier, visit https://react.dev/blog/2022/03/08/react-18-upgrade-guide for upgrade instructions.',
328329
)
329330
Error.captureStackTrace(error, renderHook)
330331
throw error
331332
}
332333

333334
const result = React.createRef()
334335

335-
function TestComponent({renderCallbackProps}) {
336+
function TestComponent({ renderCallbackProps }) {
336337
const pendingResult = renderCallback(renderCallbackProps)
337338

338339
React.useEffect(() => {
@@ -342,7 +343,7 @@ function renderHook(renderCallback, options = {}) {
342343
return null
343344
}
344345

345-
const {rerender: baseRerender, unmount} = render(
346+
const { rerender: baseRerender, unmount } = render(
346347
<TestComponent renderCallbackProps={initialProps} />,
347348
renderOptions,
348349
)
@@ -353,11 +354,11 @@ function renderHook(renderCallback, options = {}) {
353354
)
354355
}
355356

356-
return {result, rerender, unmount}
357+
return { result, rerender, unmount }
357358
}
358359

359360
// just re-export everything from dom-testing-library
360361
export * from '@testing-library/dom'
361-
export {render, renderHook, cleanup, act, fireEvent, getConfig, configure}
362+
export { render, renderHook, cleanup, act, fireEvent, getConfig, configure }
362363

363364
/* eslint func-name-matching:0 */

0 commit comments

Comments
 (0)