fix(diff): keep the load registry live across a StrictMode effect replay

StrictMode runs setup -> cleanup -> setup with no render between the two setups, so the
render-time write alone left the flag false for the life of the replayed mount and every
later reload silently bailed. Write it in both places: render covers the window where child
effects run before this parent's, the effect covers the replayed cleanup.
This commit is contained in:
Neil
2026-09-10 22:04:31 -07:00
parent 74961006e0
commit 0872c5f6ec
2 changed files with 27 additions and 3 deletions
@@ -59,8 +59,9 @@ export function useCombinedDiffSectionLoadRegistry(
loadSchedulerRef.current ??= createCombinedDiffLoadScheduler({
loadSection: (index) => loadSectionRef.current(index)
})
// Why here and not in the effect below: child effects run before this parent's, so StrictMode's
// replayed mount would leave a window where the ref reads false while the viewer is live.
// Why in render AND in the effect below: child effects run before this parent's, so a
// render-only write covers that window; StrictMode replays setup -> cleanup -> setup with no
// render in between, so an effect-only write is needed to survive the replayed cleanup.
registryLiveRef.current = true
useEffect(() => {
@@ -68,6 +69,7 @@ export function useCombinedDiffSectionLoadRegistry(
const scheduler = loadSchedulerRef.current
const reloadTimers = reloadTimersRef.current
scheduler.reset()
registryLiveRef.current = true
return () => {
registryLiveRef.current = false
clearPendingSectionReloadTimers(reloadTimers)
@@ -1,7 +1,7 @@
// @vitest-environment happy-dom
import { act, renderHook } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { useRef } from 'react'
import { StrictMode, useRef } from 'react'
import type { DiffSection } from '../../diff-section-types'
import { useCombinedDiffSectionLoadRegistry } from './combined-diff-section-load-registry'
import { useCombinedDiffSectionRetry } from './use-combined-diff-section-retry'
@@ -77,3 +77,25 @@ describe('deferred section reloads', () => {
expect(invalidate).not.toHaveBeenCalled()
})
})
it('still reloads after StrictMode replays the registry effect', () => {
// Why: StrictMode runs setup -> cleanup -> setup with no render between the two setups, so a
// render-only live flag stays false for the life of the replayed mount.
const view = renderHook(
() => {
const sectionsRef = useRef([section()])
const registry = useCombinedDiffSectionLoadRegistry(sectionsRef)
const actions = useCombinedDiffSectionRetry({
invalidateViewStateCache: invalidate,
registry,
setSectionHeights: vi.fn(),
setSections: vi.fn()
})
registry.renderedIndicesRef.current.add(0)
return actions
},
{ wrapper: StrictMode }
)
act(() => view.result.current.requestSectionReload(0))
expect(invalidate).toHaveBeenCalled()
})