Skip to content

Commit ae4f41b

Browse files
Profiling hooks compatibility (#138)
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 138e3b6 commit ae4f41b

File tree

7 files changed

+675
-90
lines changed

7 files changed

+675
-90
lines changed

exercises/06.rerenders/01.problem.memo/tests/memoized.test.ts

Lines changed: 95 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

exercises/06.rerenders/01.solution.memo/tests/memoized.test.ts

Lines changed: 95 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)