-
Notifications
You must be signed in to change notification settings - Fork 47.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug: Conditionally rendering a lazy loaded component only after the parent node is attached causes infinite loop #30582
Comments
It may not be a perfect solution, but you need to try the code below I modified. Modifyed Codeimport { Suspense, lazy, useEffect, useRef, useState } from "react";
import "./styles.css";
const LazyLoadedComponent = lazy(
() =>
new Promise((resolve) => {
setTimeout(
() =>
resolve({
default: () => (
<div style={{ background: "green" }}>Lazy loaded component</div>
)
}),
500
);
})
);
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Suspense>
<RenderAfterMount>
<LazyLoadedComponent />
</RenderAfterMount>
</Suspense>
</div>
);
}
const RenderAfterMount = (props) => {
const [node, setNode] = useState(null);
const divRef = useRef(null); // This ref references to <div> component.
// Called when the node state changes.
useEffect(() => {
if (divRef.current && !node) {
setNode(divRef.current);
}
}, [node]);
return <div ref={divRef}>{node && props.children}</div>;
}; |
Hey bro, is it still not resolved?, or are you trying? |
You might need to update const RenderAfterMount = (props) => {
const [node, setNode] = useState(null);
const popluateNode = (element) => element !== node && setNode(element);
return <div ref={popluateNode}>{node && props.children}</div>;
}; |
Thanks both, but these workarounds don't solve my issue. In my usecase I need to know about whether the parent element has been attached to the dom. Also, I believe that this is a bug, so i'm not looking for workarounds, I'm hoping to bring attention to it and get it fixed in react. In short, my usecase is a workaround for #23301, where we
|
I managed to reproduce the same issue by suspending on a simple promise instead of a lazy loaded component in the render cycle. Here's a sandbox for it: https://codesandbox.io/s/happy-williams-9yjs4p?file=/src/App.js import { Suspense, useState } from "react";
function wrapPromise(promise) {
let status = "pending";
let response;
const suspender = promise.then(
(res) => {
status = "success";
response = res;
},
(error) => {
status = "error";
response = error;
}
);
const read = () => {
switch (status) {
case "pending": {
throw suspender;
}
case "error": {
throw response;
}
default: {
return response;
}
}
};
return { read };
}
const promise = wrapPromise(
new Promise((resolve) =>
setTimeout(() => {
resolve("hello");
}, 2000)
)
);
const SuspendableComponent = () => {
const [divNode, setDivNode] = useState(null);
// removing the condition unbreaks the render
if (divNode) {
console.log(promise.read());
}
return <div ref={setDivNode} />;
};
export default function App() {
return (
<Suspense fallback={<div>loading...</div>}>
<SuspendableComponent />
</Suspense>
);
} |
So it does not need to use setState to accomplish your goal right ? |
It does need |
If I understand correctly, you can use
When your lazyComponent mounts, it will call the |
My component needs to re-render when the reference changes, therefore I need a |
Any update on this issue? |
You need to wrap <RenderAfterMount>
<Suspense>
<LazyLoadedComponent />
</Suspense>
</RenderAfterMount> Since you only have Suspense above |
That works, although if I understand correctly it means that it's not possible the whole of |
React version: 18.3.1 and 19.0.0-rc-b57d2823-20240822
Steps To Reproduce
<div>
, but only after it has obtained reference to that div (via putting the div node into a state)So basically something like:
Link to code example:
https://codesandbox.io/s/vibrant-murdock-jpnznd?file=/src/App.js:542-561
The current behavior
Runtime error due to an infinite loop.
The expected behavior
The lazy loaded component is rendered.
The text was updated successfully, but these errors were encountered: