简体   繁体   中英

Use <Component /> with dangerouslySetInnerHTML

First off, I did try looking at a few similar questions but couldn't find one that best matched my case, where I need multiple arguments.

I have a variable that contains raw HTML data, including a long paragraph that I need to truncate if it's too long. To make life simpler I'm using a module to handle this ( read-more-react ). read-more-react requires a few fields to be filled out including the text itself, and a few other fields like min and max characters before truncating.

The suggested way from Gatsby to parse raw HTML data is to use dangerouslySetInnerHTML , but I'm having some issues with including my component. I tried using the read-more-react module without dangerouslySetInnerHTML . It works, but only outputs the raw HTML " <h1>A title</h1><p>Some copy...</p> etc) without actually parsing it.

Instead, I tried this;


    <div
      className="md container"
      dangerouslySetInnerHTML={{
        __html: `
          <ReadMoreReact
            text=${htmlContent}
            min="180"
            ideal="190"
            max="200"
            readMoreText="Read more"
          />
        `,
      }}
    />

But I get a weird output;

A title

Some copy

min="180" ideal="190" max="200" readMoreText="Read more" />

So this clearly isn't working. Can anyone suggest a workaround?

read-more-react seems to handle only text, not html.
You should probably parse your html string before passing it to the ReadMoreReact component, in order to separate the paragraph from the rest and extract its text content.
Actually, you can do that using the DOM:

 const htmlString = "<h1>This is the title</h1><p>The innerText property of the HTMLElement interface represents the \"rendered\" text content of a node and its descendants. As a getter, it approximates the text the user would get if they highlighted the contents of the element with the cursor and then copied it to the clipboard.</p>" const dummyElement = document.createElement('div') dummyElement.innerHTML = htmlString; const titleText = dummyElement.querySelector('h1').innerText const pText = dummyElement.querySelector('p').innerText console.log('title ==>', titleText); console.log('p ==>', pText);

The problem is that dangerouslySetInnerHTML expects a string of normal HTML elements. Instead, you're attempting to pass in a React node which is invalid HTML(in addition ReadMoreReact returns an array of strings, which is also invalid). Instead, you can use their trimText utility function, which will do what you're expecting.

These examples use some advanced ES5+ functions:

Working example (using hooks):

编辑修剪 HTML 文本

import React from "react";
import { render } from "react-dom";
import trimText from "./utils/trimText";
import "./styles.css";

const htmlText =
  "<h2 style='display:inline;'>Lorem ipsum</h2> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";

function App() {
  const [state, setState] = React.useState({
    showOriginalHTML: false,
    originalHTML: htmlText,
    trimmedHTML: trimText(htmlText, 20, 200)[0]
  });

  const handleShowText = React.useCallback(() => {
    setState(prevState => ({
      ...prevState,
      showOriginalHTML: !prevState.showOriginalHTML
    }));
  }, [setState]);

  return (
    <div className="container">
      <div
        className="text"
        dangerouslySetInnerHTML={{
          __html: `${
            !state.showOriginalHTML ? state.trimmedHTML : state.originalHTML
          }`
        }}
      />
      <button className="read-more" onClick={handleShowText}>
        {!state.showOriginalHTML ? "read more" : "show less"}
      </button>
    </div>
  );
}

render(<App />, document.getElementById("root"));

Working example (using classes):

编辑修剪 HTML 文本 - 类

import React from "react";
import { render } from "react-dom";
import trimText from "./utils/trimText";
import "./styles.css";

const htmlText =
  "<h2 style='display:inline;'>Lorem ipsum</h2> dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";

class App extends React.Component {
  state = {
    showOriginalHTML: false,
    originalHTML: htmlText,
    trimmedHTML: trimText(htmlText, 20, 200)[0]
  };

  handleShowText = () =>
    this.setState(prevState => ({
      showOriginalHTML: !prevState.showOriginalHTML
    }));

  render = () => {
    const { originalHTML, showOriginalHTML, trimmedHTML } = this.state;

    return (
      <div className="container">
        <div
          className="text"
          dangerouslySetInnerHTML={{
            __html: `${!showOriginalHTML ? trimmedHTML : originalHTML}`
          }}
        />
        <button className="read-more" onClick={this.handleShowText}>
          {!showOriginalHTML ? "read more" : "show less"}
        </button>
      </div>
    );
  };
}

render(<App />, document.getElementById("root"));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM