@@ -12,9 +12,70 @@ test('Only ListItem should not rerender when clicking force rerender', async ({
1212 const scriptToInject = `
1313 <script>
1414 let internals
15+ const PerformedWorkFlag = 0b000000000000000000000000001
16+ const UserCodeFiberTags = new Set([0, 1, 9, 11, 15])
17+
18+ let activeFallbackComponentNames = null
19+
20+ function isUserCodeFiberTag(tag) {
21+ return UserCodeFiberTags.has(tag)
22+ }
23+
24+ function getDisplayNameFromType(type) {
25+ if (!type) return null
26+
27+ if (typeof type === 'function') {
28+ return type.displayName || type.name || null
29+ }
30+
31+ if (typeof type === 'object') {
32+ if (typeof type.displayName === 'string' && type.displayName) {
33+ return type.displayName
34+ }
35+
36+ if (typeof type.render === 'function') {
37+ return type.render.displayName || type.render.name || null
38+ }
39+
40+ if (type.type) {
41+ return getDisplayNameFromType(type.type)
42+ }
43+ }
44+
45+ return null
46+ }
47+
48+ function getFiberDisplayName(fiber) {
49+ return getDisplayNameFromType(fiber.type) || getDisplayNameFromType(fiber.elementType)
50+ }
51+
52+ function didFiberRender(previousFiber, nextFiber) {
53+ if (!previousFiber) return true
54+ return (nextFiber.flags & PerformedWorkFlag) === PerformedWorkFlag
55+ }
56+
57+ function collectRenderedComponentsFromCommit(root) {
58+ if (!activeFallbackComponentNames || !root?.current) return
59+
60+ const stack = [root.current]
61+ while (stack.length > 0) {
62+ const fiber = stack.pop()
63+ if (!fiber) continue
64+
65+ if (fiber.sibling) stack.push(fiber.sibling)
66+ if (fiber.child) stack.push(fiber.child)
67+
68+ if (!isUserCodeFiberTag(fiber.tag)) continue
69+ if (!didFiberRender(fiber.alternate, fiber)) continue
70+
71+ const componentName = getFiberDisplayName(fiber) ?? 'Anonymous'
72+ activeFallbackComponentNames.push(componentName)
73+ }
74+ }
1575
1676 function enhanceExistingHook(existingHook) {
1777 const originalInject = existingHook.inject
78+ const originalCommitFiberRoot = existingHook.onCommitFiberRoot
1879
1980 existingHook.inject = (injectedInternals) => {
2081 internals = injectedInternals
@@ -23,6 +84,12 @@ test('Only ListItem should not rerender when clicking force rerender', async ({
2384 return originalInject?.call(existingHook, injectedInternals) ?? 1
2485 }
2586
87+ existingHook.onCommitFiberRoot = (...args) => {
88+ const [, root] = args
89+ collectRenderedComponentsFromCommit(root)
90+ return originalCommitFiberRoot?.apply(existingHook, args)
91+ }
92+
2693 return existingHook
2794 }
2895
@@ -34,7 +101,9 @@ test('Only ListItem should not rerender when clicking force rerender', async ({
34101 internals = injectedInternals
35102 return 1 // Returning a number as React expects a renderer ID
36103 },
37- onCommitFiberRoot: () => {},
104+ onCommitFiberRoot: (_rendererId, root) => {
105+ collectRenderedComponentsFromCommit(root)
106+ },
38107 onCommitFiberUnmount: () => {},
39108 }
40109 }
@@ -45,19 +114,32 @@ test('Only ListItem should not rerender when clicking force rerender', async ({
45114 throw new Error('🚨 React DevTools is not available')
46115 }
47116
48- internals.enableProfilerTimer = true
49- internals.enableProfilerCommitHooks = true
50- internals.injectProfilingHooks({
51- markComponentRenderStarted: (fiber) => {
52- componentNames.push(fiber.type.name || 'Anonymous')
53- },
54- })
55-
56- await cb()
117+ const supportsInjectedProfilingHooks =
118+ typeof internals.injectProfilingHooks === 'function'
119+
120+ if (supportsInjectedProfilingHooks) {
121+ internals.enableProfilerTimer = true
122+ internals.enableProfilerCommitHooks = true
123+ internals.injectProfilingHooks({
124+ markComponentRenderStarted: (fiber) => {
125+ componentNames.push(fiber.type.name || 'Anonymous')
126+ },
127+ })
128+ } else {
129+ activeFallbackComponentNames = componentNames
130+ }
57131
58- internals.enableProfilerTimer = false
59- internals.enableProfilerCommitHooks = false
60- internals.injectProfilingHooks(null)
132+ try {
133+ await cb()
134+ } finally {
135+ if (supportsInjectedProfilingHooks) {
136+ internals.enableProfilerTimer = false
137+ internals.enableProfilerCommitHooks = false
138+ internals.injectProfilingHooks(null)
139+ } else {
140+ activeFallbackComponentNames = null
141+ }
142+ }
61143
62144 return componentNames
63145 }
0 commit comments