У меня на сервере есть предварительно отрендеренный HTML-code, полученный в результате преобразования разметки, которое я не хочу делать каждый раз.
Я знаю, как внедрить его на страницу с помощью dangerouslySetInnerHTML
, но теперь я также хочу добавить несколько компонентов React внутрь этого HTML.
Мне также удалось преобразовать компонент в строку и внедрить его в HTML с помощью:
а затем использовать HTML-парсер, такой как node-html-parser
, чтобы найти правильное место вставки, как указано в: Как использовать DOMParser в next.js?
Итак, последнее, чего не хватает, — это то, что я хочу правильно гидратировать внедренные компоненты, чтобы эффекты JavaScript были активны. В примере ниже это означает, что я хочу иметь возможность щелкнуть по простому внедренному счетчику и увеличить его значение, как и ожидалось.
Вот что я получил:
pages/index.js
но когда я пробую это, я получаю несколько ошибок в браузере:
Что я делаю не так?
package.json
next.config.js
.eslintrc
а затем я запускаю с:
Также спросили по адресу:
Похожие:
import { renderToString } from 'react-dom/server'
import { useEffect, useRef, useState } from 'react'
import { renderToString } from 'react-dom/server'
import { hydrateRoot } from 'react-dom/client'
import { parse } from 'node-html-parser'
function Counter({ initialCount }) {
const [count, setCount] = useState(initialCount)
return <button
onClick={() => setCount(i => i+1)}>Click me! {count}</button>
}
const SERVER_HTML_SELECTOR = '.second'
export default function IndexPage({ initialCount, serverHtml }) {
const serverHtmlElem = parse(serverHtml)
const clientHtmlElem = useRef(null)
serverHtmlElem.querySelector(SERVER_HTML_SELECTOR).innerHTML = renderToString(<Counter {...{ initialCount }} />)
useEffect(() => {
clientHtmlElem.current
if (clientHtmlElem.current) {
console.log(initialCount)
hydrateRoot(
clientHtmlElem.current.querySelector(SERVER_HTML_SELECTOR),
<Counter {...{ initialCount }} />
)
}
}, [initialCount, serverHtml])
return <div>
<div>Direct from React</div>
<div
dangerouslySetInnerHTML={{ __html: serverHtmlElem.outerHTML }}
ref={clientHtmlElem}
/>
</div>
}
export const getServerSideProps = async ({ params = {}, req, res }) => {
return {
props: {
// This would be dynamically fetched from the database in the actual usage.
initialCount: 10,
serverHtml: `<div>
<div class="first">I'm filled</div>
<div class="second"></div>
<div class="third">I'm also filled</div>
</div>
`,
}
}
}
{
"private": true,
"scripts": {
"dev": "next dev --turbo",
"build": "next build",
"start": "next start",
"lint": "eslint ."
},
"dependencies": {
"next": "14.2.5",
"node-html-parser": "^6.1.13",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"eslint": "7.24.0",
"eslint-config-next": "14.2.5"
}
}
module.exports = {
reactStrictMode: true,
}
{
"extends": "next",
"root": true
}
npm install
npm run dev