React version: 18.3.1
Steps To Reproduce
Create a component that renders the children inside a , but only after it has obtained reference to that div (via putting the div node into a state)
Pass a lazy loaded component as children
So basically something like:
import { Suspense, lazy, useState } from 'react';
const LazyLoadedComponent = lazy(
() =>
new Promise((resolve) => {
setTimeout(
() =>
resolve({
default: () => <div>Lazy loaded component</div>,
}),
500,
);
}),
);
const RenderAfterMount = (props) => {
const [node, setNode] = useState(null);
return <div ref={setNode}>{node && props.children}</div>;
};
export const App = () => (
<Suspense>
<RenderAfterMount>
<LazyLoadedComponent />
</RenderAfterMount>
</Suspense>
);
Link to code example:
https://stackblitz.com/edit/vitejs-vite-uqnpwm?file=src%2FApp.jsx
The current behavior
Runtime error due to an infinite loop.
The expected behavior
The lazy loaded component is rendered.
2
Answers
You can can capture the reference of the node using
const ref = useRef()
but I’m not understanding your use case here the content inside of Suspense is considered as a single unit so even if one component will take time all the other will be rendered once the one taking time resolves, in short there is no need for you to add RenderAfterMount it will just work finein this example both the text rendering and the actual lazy loaded component will be rendered after 5 seconds
The proper hook to use in this case is
useRef
. In your example thesetNode
function is, well, setting the state (value) for thenode
constant during the rendering; that process re-renders the component thus generating the infinite loop.The following code uses
useRef
hook and validates that theref
is set (node.current
) before rendering thechildren
.Hope this helps you understand and solve the problem.