const loadSettings = () => import('./Settings.jsx');
const Settings = lazy(loadSettings);
function Nav() {
const [open, setOpen] = useState(false);
return (
<>
<button onMouseEnter={loadSettings} onFocus={loadSettings}
onClick={() => setOpen(true)}>Settings</button>
{open && <Suspense fallback={<Spinner />}><Settings /></Suspense>}
</>
);
}
Start the download when the user shows intent, before the component renders. Keep the import function in a variable. Pass it to lazy, and also call it on hover or focus.
This works because the module system caches dynamic imports. Calling import('./Settings.jsx') early starts fetching the chunk. Later, Settings renders and lazy calls the same function. It gets the same module, still loading or already finished. So the fallback is short or never shown.
Other triggers:
- a link enters the viewport
- browser idle time after the main page loads
- built-in route preloading, which many routers offer
Do not preload everything, though. That wastes bandwidth on slow connections and cancels out the benefit of splitting.
- Call the import function on hover or focus.
- Reuse the same function in
lazy. - The module system caches dynamic imports.
- Other triggers are the viewport, idle time and router preloading.
- Do not preload everything.
Read more