Как внедрить компонент React в статический предварительно отрендеренный HTML-код, поступающий из базы данных в Next.js?

1
8

У меня на сервере есть предварительно отрендеренный 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
Гордей
Вопрос задан23 июня 2024 г.

1 Ответ

2
Фрол
Ответ получен16 сентября 2024 г.

Ваш ответ

Загрузить файл.