Внедрить компонент в текстовую область

#reactjs

#reactjs

Вопрос:

Мне нужно сгенерировать HTML-текст, а затем отобразить его в текстовой области, чтобы легко скопировать его.

Вот упрощенная версия моего кода (CodeSandbox):

 function Text({ foo }) {
  return (
    <>
      <h2>Title</h2>
      {foo amp;amp; <p>Foot</p>}
      <p>Baar</p>
    </>
  );
}

export default function App() {
  const [toggle, setToggle] = useState(true);

  return (
    <div className="App">
      <button
        onclick={() => {
          setToggle(!toggle);
        }}
      >
        Toogle!
      </button>
      <hr />
      <h2>Preview</h2>
      <Text foo={toggle} />
      <hr />
      <h2>HTML code :</h2>
      <textarea value={<Text foo={toggle} />} />
    </div>
  );
}
  

Компонент возвращает [object объект]. Как я могу вернуть html?

Ответ №1:

Вам нужно будет использовать ReactDOMServer.renderToString(element) для преобразования HTML-кода компонента в строку. Вы также можете присвоить компоненту переменную, чтобы гарантировать, что значение html, которым вы заполняете текстовую область, и предварительный просмотр, отображаемый в возврате, ссылаются на один и тот же экземпляр компонента.

Документация здесь: ReactDOMServer

Песочница

 import React, { useState } from "react";
import ReactDOMServer from "react-dom/server";
import "./styles.css";

function Text({ foo }) {
  return (
    <>
      <h2>Title</h2>
      {foo amp;amp; <p>Foo</p>}
      <p>Baar</p>
    </>
  );
}

export default function App() {
  const [toggle, setToggle] = useState(true);

  const element = <Text foo={toggle} />;
  const html = ReactDOMServer.renderToString(element);

  console.log(element);
  return (
    <div className="App">
      <button
        onClick={() => {
          setToggle(!toggle);
        }}
      >
        Toogle!
      </button>
      <hr />

      <h2>Preview</h2>
        {element}
      <hr />

      <h2>HTML code :</h2>
      <textarea value={html} />
    </div>
  );
}
  

Ответ №2:

Я не думаю, что вы сможете это сделать, поскольку это не HTML семантически корректно. Я попытался отредактировать ваш CodeSendbox, чтобы поместить внутри текстовой области dangerouslySetInnerHTML, и он отобразил сообщение о том, что нет смысла отображать html-элементы внутри текстовой области. Что вы можете сделать, это использовать некоторый div вместо textarea и предоставить ему несколько классов css, чтобы он выглядел как textarea, и поместить в него contenteditable в качестве атрибута, вот так:

 export default function App() {
  const [toggle, setToggle] = useState(true);

  return (
    <div className="App">
      <button
        onClick={() => {
          setToggle(!toggle);
        }}
      >
        Toogle!
      </button>
      <hr />

      <h2>Preview</h2>
      <Text foo={toggle} />
      <hr />

      <h2>HTML code :</h2>
      <div contentEditable className="divAsTextarea">
        <Text foo={toggle} />
      </div>
    </div>
  );
}