Can a lazy loaded component have a lazy loaded component inside it?
Example:
const LazyLoaded = lazy(() => import('./path'));
const App = () => {
return (
<>
<Suspense fallback={<div>Loading</div>}>
<LazyLoaded />
</Suspense>
</>
);
}
and LazyLoaded
component:
const LazyChild = lazy(() => import("./another-path"));
const Lazy = () => {
return (
<>
// another markup for example
<Suspense fallback={<div>Child loading</div>}>
<LazyChild />
</Suspense>
</>
);
}
Is it possible? This does not seem to be working for me, LazyChild
is ready whenever the parent is.
Lazy components can go in lazy components. I suspect the effect you're observing with React not displaying the fallback for the lazily loaded child is because the DOM updates got batched and the intermediate update that would've shown the fallback for the lazily loaded child got discarded. I've created a demo that shows the fallback for the lazily loaded child given enough time:
2000
ms delay. You can change it to something else if you'd like.At this point you can observe all fallbacks being rendered and applied to the DOM. To reset everything press Run code snippet again.
Unfortunately, I can't give more concrete details on exactly why/how the batching is happening. debugger
statements have been set up in the demo however I don't have time right now to dig into this in more detail. You may do so if you wish.
const { createRoot } = ReactDOM;
const { Fragment, StrictMode, Suspense, lazy } = React;
function delay(promise) {
const time = document.getElementById("delay").value;
return new Promise((resolve) => {
setTimeout(resolve, time);
}).then(() => promise);
}
const LazyChild = lazy(() => {
debugger;
return delay(Promise.resolve({
default: function LazyChild() {
debugger;
return <div>LazyChild</div>;
}
}));
});
function LazyChildFallback() {
return <div style={{ backgroundColor: "red" }} className="fallback">Lazy Child Fallback</div>;
}
const LazyParent = lazy(() => {
debugger;
return delay(Promise.resolve({
default: function LazyParent() {
debugger;
return (
<Fragment>
<Suspense fallback={<LazyChildFallback />}>
<LazyChild />
</Suspense>
</Fragment>
);
}
}));
});
function LazyParentFallback() {
return <div style={{ backgroundColor: "blue" }} className="fallback">Lazy Parent Fallback</div>;
}
function App() {
return (
<Fragment>
<Suspense fallback={<LazyParentFallback />}>
<LazyParent />
</Suspense>
</Fragment>
);
};
let root;
let rootElement;
function render() {
if (root && rootElement) {
console.log("Press \"Run code snippet\" button to reset");
return;
}
rootElement = document.createElement("div");
rootElement.setAttribute("id", "root");
document.body.appendChild(rootElement);
root = createRoot(rootElement);
root.render(<StrictMode><App /></StrictMode>);
}
document.getElementById("render").addEventListener("click", render);
body {
font-family: sans-serif;
}
#root {
margin: 20px 0;
}
.fallback {
height: 50vh;
width: 100%;
}
<input id="delay" name="delay" type="number" value="2000" />
<button id="render">Render</button>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>