Skip to content

Instantly share code, notes, and snippets.

@tusharsnx
Created August 18, 2025 15:02
Show Gist options
  • Select an option

  • Save tusharsnx/13b4410c5dbf32510a332766c9d3edf5 to your computer and use it in GitHub Desktop.

Select an option

Save tusharsnx/13b4410c5dbf32510a332766c9d3edf5 to your computer and use it in GitHub Desktop.
An alternative suspense boundary which hides the components from DOM while they are loading
import { useEffect, useState } from "react";
import { useActivateLoaderBoundary } from "#/components/suspense-activity";
export function useResource<T>({
load,
unload,
}: {
load: () => Promise<T> | T;
unload?: () => Promise<void> | void;
}) {
const [asyncState, setAsyncState] = useState<T | null>(null);
// Get the boundary activator.
const activate = useActivateLoaderBoundary();
useEffect(() => {
let cancelled = false;
async function loadResource() {
const result = await load();
if (cancelled) {
return;
}
setAsyncState(result);
}
const deactivate = activate(loadResource);
return () => {
cancelled = true;
deactivate();
};
}, [load, activate]);
return [asyncState === null, asyncState] as const;
}
async function loadData() {
await new Promise((resolve) => setTimeout(resolve, 2000));
return "Data loaded 4";
}
export function VideoComponent() {
// We should get whether we need to show the loading state or not from the SuspenseAltContext.
const [isLoading, asyncState] = useResource({ load: loadData });
if (isLoading) {
// This is not visible in the DOM.
return <div>VideoComponent Loading...</div>;
}
return (
<div>
<p>{asyncState}</p>
</div>
);
}
"use client";
import { createContext, type ReactNode, use, useRef, useState } from "react";
type Deactivate = () => void;
type LoaderBoundaryActivate = (cb: () => Promise<void> | void) => Deactivate;
const LoaderBoundaryContext = createContext<LoaderBoundaryActivate | null>(
null,
);
export function useActivateLoaderBoundary() {
const context = use(LoaderBoundaryContext);
if (!context) {
throw new Error(
"useSuspenseTransition must be used within a SuspenseAltProvider",
);
}
return context;
}
export function LoaderBoundary({
children,
fallback,
}: {
children: ReactNode;
fallback?: ReactNode;
}) {
const [isPending, setIsPending] = useState(false);
const suspendedActivityCountRef = useRef(0);
function activate(cb: () => Promise<void> | void) {
setIsPending(true);
suspendedActivityCountRef.current += 1;
let unsuspended = false;
function unsuspend() {
if (unsuspended) {
return;
}
unsuspended = true;
suspendedActivityCountRef.current -= 1;
if (suspendedActivityCountRef.current === 0) {
setIsPending(false);
}
}
void Promise.resolve().then(cb).finally(unsuspend);
return unsuspend;
}
return (
<LoaderBoundaryContext value={activate}>
{/* When pending, children will still be part of the HTML tree, but not the visual tree. */}
<div style={{ display: isPending ? "none" : "contents" }}>{children}</div>
{/* Fallback is only shown when we're pending */}
{isPending && fallback}
</LoaderBoundaryContext>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment