diff --git a/packages/@react-facet/deferred-mount/src/index.spec.tsx b/packages/@react-facet/deferred-mount/src/index.spec.tsx
index 7e0dcf83..ada7ef91 100644
--- a/packages/@react-facet/deferred-mount/src/index.spec.tsx
+++ b/packages/@react-facet/deferred-mount/src/index.spec.tsx
@@ -16,6 +16,27 @@ interface Cb {
frameId: number
}
+jest.useFakeTimers()
+
+const frames: (() => void)[] = []
+const requestSpy = jest.spyOn(window, 'requestAnimationFrame').mockImplementation((frameRequest) => {
+ const id = idSeed++
+ const cb = () => {
+ frameRequest(id)
+ }
+ frames.push(cb)
+ return id
+})
+
+const runRaf = () => {
+ const cb = frames.pop()
+ if (cb != null) act(() => cb())
+}
+
+afterEach(() => {
+ requestSpy.mockClear()
+})
+
describe('DeferredMount', () => {
it('renders immediately if we dont have a provider', () => {
const { container } = render(
@@ -25,9 +46,69 @@ describe('DeferredMount', () => {
)
expect(container.firstChild).toContainHTML('
Should be rendered
')
})
+
+ it('defers again after initial defer has completed', () => {
+ const DeferConditionally: React.FC<{ mountDeferred: boolean }> = ({ mountDeferred }) => {
+ const isDeferringFacet = useIsDeferring()
+ return (
+ <>
+ (isDeferring ? 'deferring' : 'done'), [], [isDeferringFacet])}
+ />
+ {mountDeferred && (
+
+ Conditionally rendered
+
+ )}
+ >
+ )
+ }
+
+ const { container, rerender } = render(
+
+
+ ,
+ )
+
+ expect(container).toContainHTML('deferring')
+ expect(container).not.toContainHTML('Conditionally rendered
')
+
+ runRaf()
+ expect(container).toContainHTML('done')
+ expect(container).not.toContainHTML('Conditionally rendered
')
+
+ rerender(
+
+
+ ,
+ )
+
+ expect(container).toContainHTML('deferring')
+ expect(container).not.toContainHTML('Conditionally rendered
')
+
+ runRaf()
+ expect(container).toContainHTML('done')
+ expect(container).toContainHTML('Conditionally rendered
')
+ })
})
describe('DeferredMountWithCallback', () => {
+ const MOUNT_COMPLETION_DELAY = 1000
+
+ const MockDeferredComponent = ({ index }: { index: number }) => {
+ const triggerMountComplete = useNotifyMountComplete()
+
+ useEffect(() => {
+ const id = setTimeout(triggerMountComplete, MOUNT_COMPLETION_DELAY)
+
+ return () => {
+ clearTimeout(id)
+ }
+ }, [triggerMountComplete, index])
+
+ return Callback{index}
+ }
+
it('renders immediately if we dont have a provider', () => {
const { container } = render(
@@ -37,61 +118,26 @@ describe('DeferredMountWithCallback', () => {
expect(container.firstChild).toContainHTML('Should be rendered
')
})
- it('waits until previous deferred callback finishes', async () => {
- jest.useFakeTimers()
-
- const frames: (() => void)[] = []
- const requestSpy = jest.spyOn(window, 'requestAnimationFrame').mockImplementation((frameRequest) => {
- const id = idSeed++
- const cb = () => {
- frameRequest(id)
- }
- frames.push(cb)
- return id
- })
-
- const runRaf = () => {
- const cb = frames.pop()
- if (cb != null) act(() => cb())
- }
-
- const MOUNT_COMPLETION_DELAY = 1000
-
- const MockDeferredComponent = ({ index }: { index: number }) => {
- const triggerMountComplete = useNotifyMountComplete()
-
- useEffect(() => {
- const id = setTimeout(triggerMountComplete, MOUNT_COMPLETION_DELAY)
-
- return () => {
- clearTimeout(id)
- }
- }, [triggerMountComplete, index])
-
- return Callback{index}
- }
-
- const SampleComponent = () => {
- const isDeferringFacet = useIsDeferring()
+ const SampleComponent = () => {
+ const isDeferringFacet = useIsDeferring()
- return (
- <>
- (isDeferring ? 'deferring' : 'done'), [], [isDeferringFacet])}
- />
-
-
-
-
-
-
-
-
-
- >
- )
- }
+ return (
+ <>
+ (isDeferring ? 'deferring' : 'done'), [], [isDeferringFacet])} />
+
+
+
+
+
+
+
+
+
+ >
+ )
+ }
+ it('waits until previous deferred callback finishes', async () => {
const { container } = render(
@@ -128,9 +174,6 @@ describe('DeferredMountWithCallback', () => {
jest.advanceTimersByTime(MOUNT_COMPLETION_DELAY)
runRaf()
expect(container).toContainHTML('done')
-
- jest.useRealTimers()
- requestSpy.mockRestore()
})
})
diff --git a/packages/@react-facet/deferred-mount/src/index.tsx b/packages/@react-facet/deferred-mount/src/index.tsx
index 74bddcbe..a69b9710 100644
--- a/packages/@react-facet/deferred-mount/src/index.tsx
+++ b/packages/@react-facet/deferred-mount/src/index.tsx
@@ -43,7 +43,6 @@ export function InnerDeferredMountProvider({
frameTimeBudget = DEFAULT_FRAME_TIME_BUDGET,
}: DeferredMountProviderProps) {
const [isDeferring, setIsDeferring] = useFacetState(true)
- const [requestingToRun, setRequestingToRun] = useFacetState(false)
const waitingForMountCallback = useRef(false)
const deferredMountsRef = useRef([])
@@ -51,7 +50,7 @@ export function InnerDeferredMountProvider({
const pushDeferUpdateFunction = useCallback(
(updateFn: UpdateFn) => {
// Causes a re-render of this component that will kick-off the effect below
- setRequestingToRun(true)
+ setIsDeferring(true)
deferredMountsRef.current.push(updateFn)
@@ -69,14 +68,14 @@ export function InnerDeferredMountProvider({
}
}
},
- [setRequestingToRun],
+ [setIsDeferring],
)
useFacetEffect(
- (requestingToRun) => {
+ (isDeferring) => {
// Even if we are not considered to be running, we need to check if there is still
// work pending to be done. If there is... we still need to run this effect.
- if (!requestingToRun && deferredMountsRef.current.length === 0 && !waitingForMountCallback.current) return
+ if (!isDeferring && deferredMountsRef.current.length === 0 && !waitingForMountCallback.current) return
const work = (startTimestamp: number) => {
const deferredMounts = deferredMountsRef.current
@@ -131,7 +130,6 @@ export function InnerDeferredMountProvider({
if (deferredMounts.length === 0 && !waitingForMountCallback.current) {
setIsDeferring(false)
- setRequestingToRun(false)
}
}
@@ -141,8 +139,8 @@ export function InnerDeferredMountProvider({
window.cancelAnimationFrame(frameId)
}
},
- [frameTimeBudget, setIsDeferring, setRequestingToRun],
- [requestingToRun],
+ [frameTimeBudget, setIsDeferring],
+ [isDeferring],
)
return (