EDIT: better explanation
The context:
I receive some plain HTML code from a 3rd server, which I want to
The vanilla JS approach
idgetElementById, as usualThe React approach
ReactDOMServer.renderToStringReactDOM.render(), the problem is that the render method takes its time, so that if in the next line I try to use the ref that exists in the inserted component, is not yet thereThe question
useEffect with a [] dependencies, but here I am rendering the component when the app is already mountedref, but for sure there has to be something betterThis code fails, because when the ref is rendered it is still not available, so ref.current is undefined
How can I wait for it?
codesandbox
EDIT: I provide the code that works but through direct DOM, which I assume should be avoided
import React, { useRef, useEffect } from "react";
import ReactDOM from "react-dom";
export default function App() {
const myref = useRef();
useEffect(() => {
const Com = () => <div ref={myref}>hello</div>;
ReactDOM.render(<Com />, document.getElementById("container"));
console.log(myref.current); // undefined
document.getElementById('container').textContent = "direct DOM works"
// the next line fails since the ref is not yet available
// myref.current.textContent = "but this REF is not available"; // fails
}, []);
const plainhtml = '<div><div id="container"></div><div>some more content</div><div id="another">even more content</div></div>'; // this is some large HTML fetched from an external server
return (
<div>
<h1>Hello CodeSandbox</h1>
<div dangerouslySetInnerHTML={{ __html: plainhtml }} />
</div>
);
}
useEffect with empty dependency array executes after the first render, therefore you will get the DOM ref in the callback:
const htmlString = '<div id="container">Hello</div>';
export default function App() {
const myRef = useRef();
useEffect(() => {
if (myRef.current) {
myRef.current.textContent = 'whats up';
}
console.log(myRef.current);
}, []);
return (
<div>
<div ref={myRef} dangerouslySetInnerHTML={{ __html: htmlString }} />
<div dangerouslySetInnerHTML={{ __html: htmlString }} />
</div>
);
}
/* App renders:
whats up
Hello
*/
I need to use a callback ref but encapsulating it within useCallback to make sure it only rerenders with the dependencies indicated (i.e. none []), so that it is only executed when the component changes (as explained here)
codesandbox
import React, { useEffect, useCallback } from "react";
import ReactDOM from "react-dom";
export default function App() {
const measuredRef = useCallback(node => {
if (node !== null) {
node.textContent = "useCallback DOM also works";
}
}, []);
useEffect(() => {
const Com = () => <div ref={measuredRef}>hello</div>;
ReactDOM.render(<Com />, document.getElementById("container"));
document.getElementById("container").textContent = "direct DOM works";
}, []);
const plainhtml = '<div id="container"></div>';
return (
<div>
<h1>Hello CodeSandbox</h1>
<div dangerouslySetInnerHTML={{ __html: plainhtml }} />
</div>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With