javascript - Hur renderar man HTML-sträng som riktig HTML?


Här är vad jag försökte och hur det går fel.

Det här fungerar:

<div dangerouslySetInnerHTML={{ __html: "<h1>Hi there!</h1>" }} />

Detta gör inte:

<div dangerouslySetInnerHTML={{ __html: this.props.match.description }} />

Egenskapen description är bara en vanlig sträng med HTML-innehåll. Dock renderas den som en sträng, inte som HTML av någon anledning.

Några förslag?

Svar #1

Är this.props.match.description en sträng eller ett objekt? Om det är en sträng bör det kunna konverteras till HTML utan problem. Exempel:

class App extends React.Component {

constructor() {
    super();
    this.state = {
      description: '<h1 style="color:red;">something</h1>'
    }
  }
  
  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.state.description }} />
    );
  }
}

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

Resultat: http://codepen.io/ilanus/pen/QKgoLA?editors=1011

Men om beskrivningen är <h1 style="color:red;">något</h1> utan citattecknen '', kommer du att få:

Object {
$$typeof: [object Symbol] {},
  _owner: null,
  key: null,
  props: Object {
    children: "something",
    style: "color:red;"
  },
  ref: null,
  type: "h1"
}

Om det är en sträng och du inte ser någon HTML-markering är det enda problemet jag ser felaktig markering..

UPPDATERING

Om du hanterar HTML-enheter måste du avkoda dem innan du skickar dem till dangerouslySetInnerHTML, det är därför det kallas "farligt" :)

Arbetande exempel:

class App extends React.Component {

  constructor() {
    super();
    this.state = {
      description: '&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;'
    }
  }

   htmlDecode(input){
    var e = document.createElement('div');
    e.innerHTML = input;
    return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
  }

  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.htmlDecode(this.state.description) }} />
    );
  }
}

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

Svar #2

Jag använder 'react-html-parser'

yarn add react-html-parser
import ReactHtmlParser from 'react-html-parser'; 

<div> { ReactHtmlParser (html_string) } </div>

Källa på npmjs.com

Lyfter upp @okram:s kommentar för mer synlighet:

från dess GitHub-beskrivning: Konverterar HTML-strängar direkt till React-komponenter och undviker behovet av att använda dangerouslySetInnerHTML från npmjs.com Ett verktyg för att konvertera HTML-strängar till React-komponenter. Undviker användning av dangerouslySetInnerHTML och konverterar standard HTML-element, attribut och inline-stilar till deras React-motsvarigheter.

Svar #3

Kontrollera att texten du försöker lägga till noden inte är escaped på detta sätt:

var prop = {
    match: {
        description: '&lt;h1&gt;Hi there!&lt;/h1&gt;'
    }
};

Istället för detta:

var prop = {
    match: {
        description: '<h1>Hi there!</h1>'
    }
};

om det är escapade bör du konvertera det från din server-sida.

Noden är text eftersom den är undflydd

Noden är en DOM-nod eftersom den inte är escapad

Svar #4

Om du har HTML i en sträng skulle jag rekommendera att använda ett paket som kallas html-react-parser.

Installation

NPM :

npm install html-react-parser

garn :

yarn add html-react-parser

Användning

import parse from 'html-react-parser'
const yourHtmlString = '<h1>Hello</h1>'

kod :

<div>
    {parse(yourHtmlString)}
</div>

Svar #5

Jag använder innerHTML tillsammans med en referens till span:

import React, { useRef, useEffect, useState } from 'react';

export default function Sample() {
  const spanRef = useRef<HTMLSpanElement>(null);
  const [someHTML,] = useState("some <b>bold</b>");

  useEffect(() => {
    if (spanRef.current) {
      spanRef.current.innerHTML = someHTML;
    }
  }, [spanRef.current, someHTML]);

  return <div>
    my custom text follows<br />
    <span ref={spanRef} />
  </div>
}

notering om XSS-attack: för att förhindra att skadlig injicerad kod körs måste HTML-koden saneras. Se följande exempel:

/**
 * example how to retrieve a reference to an html object
 */

import React, { useRef, useEffect } from 'react';
import * as DOMPurify from 'dompurify'; // add with yarn add DOMPurify and @types/DOMPurify

/**
 * this component can be used into another for example <Sample/>
 */
export default function Sample() {
    /**
     * 1) spanRef is now a React.RefObject<HTMLSpanElement>
     * initially created with null value
     */
    const spanRef = useRef<HTMLSpanElement>(null);

    /**
     * 2) later, when spanRef changes because html span element with ref attribute,
     * follow useEffect hook will triggered because of dependent [spanRef].
     * in an if ( spanRef.current ) that states if spanRef assigned to valid html obj
     * we do what we need : in this case through current.innerHTML
     */
    useEffect(() => {
        if (spanRef.current) {
            // follow malicious code injects
            // spanRef.current.innerHTML = "sample xss<img src onerror=\"alert('code exec')\"/>";

            // follow malicious code will sanitized to <img src>
            spanRef.current.innerHTML = DOMPurify.sanitize("sample xss prevented<img src onerror=\"alert('code exec')\"/>")
        }
    }, [spanRef]);

    return <div>
        my custom text follows<br />
        {/* ref={spanRef] will update the React.RefObject `spanRef` when html obj ready */}
        <span ref={spanRef} />
    </div>
}

Svar #6

Om du har kontroll över var strängen som innehåller HTML kommer ifrån (dvs. någonstans i din app), kan du dra nytta av det nya <Fragment>-API:et genom att göra något i stil med:

import React, {Fragment} from 'react'

const stringsSomeWithHtml = {
  testOne: (
    <Fragment>
      Some text <strong>wrapped with strong</strong>
    </Fragment>
  ),
  testTwo: `This is just a plain string, but it'll print fine too`,
}

...

render() {
  return <div>{stringsSomeWithHtml[prop.key]}</div>
}

Svar #7

Du använder bara Reacts metod dangerouslySetInnerHTML

<div dangerouslySetInnerHTML={{ __html: htmlString }} />

Eller så kan du implementera mer på detta enkla sätt: Rendera HTML rå i React-appen

Relaterade artiklar