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: '<p><strong>Our Opportunity:</strong></p>'
}
}
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: '<h1>Hi there!</h1>'
}
};
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


