Skip to main content

useDeferredComponent

The useDeferredComponent hook dynamically imports a component and renders it only after the host component has mounted on the client. On the server — and on the first client render, matching SSR — it returns null, so there is no hydration mismatch and the imported chunk stays out of the initial/critical path (the bundler still code-splits the dynamic import(), which is only invoked after hydration).

Use it for fire-and-forget, no-UI client trackers (analytics, speed insights) or any strictly client-side / below-the-fold widget whose code should not ship in the initial bundle.

import { useDeferredComponent } from '@archibald/client';

const Component = useDeferredComponent(FACTORY);

Parameters

NameTypeDescription
factory() => Promise<{ default: ComponentType<P> }>A dynamic import returning a module with a default-exported component. Invoked once, on mount (later identities are ignored).

Return value

TypeDescription
ComponentType<P> | nullThe loaded component, or null until it is imported after mount.

useDeferredComponent vs React.lazy

Prefer useDeferredComponent when the component must not run during SSR or hydration. React.lazy + Suspense resolves on the server and loads during hydration (nearer the critical path, and it needs a Suspense boundary). useDeferredComponent renders null through SSR and the first client render, then loads strictly after mount — ideal for code that has no UI and should never block first paint.

Example

import { useDeferredComponent } from '@archibald/client';

// AnalyticsImpl and its heavy dependencies are code-split into an async chunk that is
// fetched only after hydration — never part of the initial/critical payload.
function Analytics() {
const Impl = useDeferredComponent(() => import('./AnalyticsImpl'));
return Impl ? <Impl /> : null;
}

export default Analytics;