[Next.js 14 / React 18] How to migrate from renderToStaticMarkup
method on the Client side?
#58533
Answered
by
yakovenkomax
BorysShulyak
asked this question in
Help
Replies: 4 comments 6 replies
-
if it could help, this is how I fixed async function simpleRenderToString(element: React.ReactElement) {
const container = document.createElement("div")
const root = ReactDOM.createRoot(container)
root.render(element)
return new Promise<string>(resolve => {
setTimeout(() => {
resolve(container.innerHTML)
}, 100)
})
} |
Beta Was this translation helpful? Give feedback.
2 replies
-
While it is not always possible, you can use portals for most cases I think. "use client";
import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
export default function Home() {
const [host, setHost] = useState<HTMLElement | null>(null);
useEffect(() => {
const element = document.createElement("div");
setHost(element);
}, []);
return (
<div>
{host && createPortal(<p>Hello world</p>, host)}
<button
onClick={() => {
console.log(host?.innerHTML);
}}
>
Print HTML to console
</button>
</div>
);
} |
Beta Was this translation helpful? Give feedback.
0 replies
-
This works for me: const renderToString = async (element: React.ReactElement) => {
const container = document.createElement('div');
ReactDOM.render(element, container);
await new Promise(resolve => setTimeout(resolve, 100)); // wait for the rendering to complete
const html = container.innerHTML;
root.unmount();
return html;
}; The solution I mentioned in previous issue #57669 does not work well. |
Beta Was this translation helpful? Give feedback.
0 replies
-
// clientRenderToString.tsx
export const clientRenderToString = (element: React.ReactElement): Promise<string> =>
new Promise(resolve => {
const container = document.createElement('div');
const renderCallback = () => {
resolve(container.firstElementChild?.innerHTML || '');
};
ReactDOM.createRoot(container).render(<div ref={renderCallback}>{element}</div>);
}); // useClientRenderToString.ts
type UseClientRenderToString = (
input: React.ReactElement | React.ReactElement[],
deps?: any[]
) => string[];
export const useClientRenderToString: UseClientRenderToString = (input, deps = []) => {
const [htmlStringList, setHtmlStringList] = useState<string[]>([]);
const elementList = Array.isArray(input) ? input : [input];
useEffect(() => {
(async () => {
const markupPromises = elementList.map(clientRenderToString);
const markup: string[] = await Promise.all(markupPromises);
if (!setHtmlStringList) {
return;
}
setHtmlStringList(markup);
})();
}, deps);
return htmlStringList;
}; // usage
// single element
const [singleElementMarkup] = useClientRenderToString(<Text value="world" />);
// multiple elements
const multipleElements = ["some", "other", "text"].map((text) => (
<Text value={text} />
));
const multipleElementsMarkup = useClientRenderToString(multipleElements); Example: https://codesandbox.io/p/sandbox/clientrendertostring-lw8zkc |
Beta Was this translation helpful? Give feedback.
4 replies
Answer selected by
BorysShulyak
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Summary
Based on the React documentation, version 18 has limited
renderToStaticMarkup
api.We use this method on the client side for emails rendering and it doesn't work after upgrading to Next.js
v14.x.x
. So it is blocker for the package updates.Here we have a well described related issue. It is already closed, but many people still could not deal with replacing this method on the client side.
Could you provide the migration guide for
renderToStaticMarkup
method on the client side, please?Additional information
Example
https://codesandbox.io/p/sandbox/busy-bohr-xyz6rn?file=%2Fapp%2Fpage.tsx%3A15%2C1
Beta Was this translation helpful? Give feedback.
All reactions