แสดงผลสตริง HTML เป็น HTML จริงในองค์ประกอบ React


160

นี่คือสิ่งที่ฉันพยายามและมันผิดพลาดอย่างไร

งานนี้:

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

สิ่งนี้ไม่:

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

คุณสมบัติคำอธิบายเป็นเพียงสตริงปกติของเนื้อหา HTML อย่างไรก็ตามมันแสดงผลเป็นสตริงไม่ใช่ HTML ด้วยเหตุผลบางประการ

ป้อนคำอธิบายรูปภาพที่นี่

ข้อเสนอแนะใด ๆ

คำตอบ:


50

ตรวจสอบว่าข้อความที่คุณพยายามผนวกเข้ากับโหนดไม่ได้รับการยกเว้นดังนี้:

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

แทนสิ่งนี้:

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

ถ้าหนีคุณควรแปลงจากฝั่งเซิร์ฟเวอร์ของคุณ

โหนดเป็นข้อความเพราะจะถูกหลบหนี

โหนดเป็นข้อความเพราะจะถูกหลบหนี

โหนดเป็นโหนด dom เพราะไม่ได้หลบหนี

โหนดเป็นโหนด dom เพราะไม่ได้หลบหนี


3
นี่คือปัญหา สตริงคำอธิบายหนีออกมาเป็น HTML ฉันไม่ใช้ Escape และตอนนี้ก็ใช้ได้ดี
Sergio Tapia

4
โปรดหลีกเลี่ยงการใช้dangerouslySetInnerHTMLแทนการใช้Fragmentจาก react v16 ตรวจสอบคำตอบถัดไปโดย @ brad-adams
Kunal Parekh

2
ขอบคุณที่กล่าวถึง @KunalParekh แต่พวกเขาต่างกัน คำตอบของฉันใช้ได้เฉพาะในกรณีที่ html นั้นอยู่ในแอพของคุณ (หมายถึงมันคือ JSX จริง ๆ ) ในการแยก HTML จากแหล่งภายนอกไปยัง jsx คุณต้องหาวิธีแก้ไขอื่น
แบรดอดัมส์

113

ไม่this.props.match.descriptionเป็นสตริงหรือวัตถุ? หากเป็นสตริงควรแปลงเป็น HTML ได้ ตัวอย่าง:

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'));

ผลลัพธ์: http://codepen.io/ilanus/pen/QKgoLA?editors=1011

อย่างไรก็ตามหากdescription: <h1 style="color:red;">something</h1>ไม่มีคำพูด''คุณจะได้รับ:

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

หากเป็นสตริงและคุณไม่เห็นมาร์กอัป HTML ใด ๆ ปัญหาเดียวที่ฉันเห็นคือมาร์กอัปผิดพลาด ..

UPDATE

หากคุณกำลังติดต่อกับ HTMLEntitles คุณต้องถอดรหัสพวกเขาก่อนที่จะส่งพวกเขาไปdangerouslySetInnerHTMLที่นั่นคือเหตุผลที่พวกเขาเรียกมันว่าอันตราย :)

ตัวอย่างการทำงาน:

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'));

this.props.match.descriptionเป็นสตริงไม่ใช่วัตถุ คุณหมายถึงอะไรกับมาร์กอัปที่ผิด? คุณหมายถึง unclosed tags หรือเปล่า ปฏิกิริยาควรแสดงมันไม่?
Sergio Tapia

คุณสามารถวางที่นี่ console.log (this.props.match.description);
Ilanus

ตัวอย่างหนึ่ง:&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;
Sergio Tapia

ในกรณีนี้คุณต้องใช้. innerHTML หรือถอดรหัส HTMLEntities
Ilanus

ส่งคืนหลายบรรทัดหรือรหัส HTML ด้วยแท็ก: ฟังก์ชัน htmlDecode (อินพุต) {var e = document.createElement ('div'); e.innerHTML = อินพุต; var returnString = ''; สำหรับ (index = 0; index <e.childNodes.length; index ++) {// กรณีของสตริงเพียงถ้า (e.childNodes [index] .nodeValue) {returnString + = e.childNodes [index] .nodeValue; } // กรณีของ HTML ถ้า (e.childNodes [index] .outerHTML) {returnString + = e.childNodes [index] .outerHTML; }} return returnString; }
Chris Adams

58

ฉันใช้ 'react-html-parser'

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

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

แหล่งที่มาบน npmjs.com

การยกความคิดเห็นของ @ okram เพื่อให้มองเห็นได้ชัดเจนขึ้น:

จากคำอธิบาย github: แปลงสตริง HTML โดยตรงไปยังส่วนประกอบ React หลีกเลี่ยงความจำเป็นในการใช้ dangerlySetInnerHTML จาก npmjs.com ยูทิลิตี้สำหรับการแปลงสตริง HTML เป็นส่วนประกอบ React หลีกเลี่ยงการใช้ dangerlySetInnerHTML และแปลงองค์ประกอบ HTML มาตรฐานคุณลักษณะและรูปแบบอินไลน์เป็นสิ่งที่เทียบเท่ากับ React


11
ไลบรารีนี้ใช้ "dangerlySetInnerHTML" ในพื้นหลังหรือไม่
โอมาร์

1
จากคำอธิบาย github: Converts HTML strings directly into React components avoiding the need to use dangerouslySetInnerHTMLจาก npmjs.comA utility for converting HTML strings into React components. Avoids the use of dangerouslySetInnerHTML and converts standard HTML elements, attributes and inline styles into their React equivalents.
okram

14

หากคุณสามารถควบคุมได้ว่าสตริงที่มี html นั้นมาจากที่ไหน (เช่นที่ใดที่หนึ่งในแอปของคุณ) คุณสามารถได้รับประโยชน์จาก<Fragment>API ใหม่โดยทำสิ่งต่อไปนี้:

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>
}

11
ไม่มีสตริงที่มี html ในตัวอย่างของคุณ มันเป็น jsx หรือสตริงธรรมดา
mrkvon

3
ใช่แล้วในทางเทคนิคคุณถูกต้อง @mrkvon แต่ตามที่ฉันพูดถึงวิธีการแก้ปัญหานี้จะใช้ได้เฉพาะเมื่อพูดว่า "html" / jsx เป็นสิ่งที่คุณสามารถควบคุมได้ ไม่ใช่เพื่อการแสดงผลhtml ดิบบางอย่างที่มีให้ผ่าน API ตัวอย่างเช่น ก่อนหน้าFragmentAPI มันเป็นความเจ็บปวดสำหรับฉันเสมอซึ่งต้องมีการspanตัดคำเพิ่มเติมที่บางครั้งอาจยุ่งกับเค้าโครงแบบยืดหยุ่น เมื่อฉันสะดุดคำถามนี้เพื่อมองหาทางออกที่เป็นไปได้ฉันคิดว่าฉันจะแบ่งปันสิ่งที่ฉันได้รับ
แบรดอดัมส์

2
ขอบคุณ! นี่เป็นทางออกเดียวที่ทำงานในกรณีของฉัน นอกจากนี้การตอบสนองต่อความคิดเห็น mrkvon ในคำตอบนี้: คำตอบนี้แน่นอนมี HTML คือมีแท็กSome text <strong>wrapped with strong</strong> HTML strong
Binita Bharati

@BinitaBharati แต่นั่นไม่ใช่สตริง หากคุณได้รับสตริงจาก API เช่น "<p> นี่คือสตริง </p>" (หรือเก็บสตริงไว้ในตัวแปร) เมื่อคุณใส่สตริงนี้ใน <Fragment> ผลลัพธ์จะยังคงมี < แท็ก>
Muchdecal

1
@BradAdams เคล็ดลับดีนะ ฉันสามารถดูกรณีที่เป็นประโยชน์
Muchdecal


5

dangerouslySetInnerHTML

dangerlySetInnerHTML ถูกแทนที่ด้วย React สำหรับการใช้ innerHTML ในเบราว์เซอร์ DOM โดยทั่วไปแล้วการตั้งค่า HTML จากรหัสนั้นมีความเสี่ยงเพราะเป็นการง่ายที่จะทำให้ผู้ใช้ของคุณถูกโจมตีแบบข้ามไซต์ (XSS) ดังนั้นคุณสามารถตั้งค่า HTML ได้โดยตรงจาก React แต่คุณต้องพิมพ์ dangerlySetInnerHTML และส่งวัตถุด้วยคีย์ __html เพื่อเตือนตัวเองว่ามันอันตราย ตัวอย่างเช่น:

function createMarkup() {
  return {__html: 'First &middot; Second'};
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

3

ฉันใช้ innerHTML ร่วมกันเพื่ออ้างอิง:

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>
}

ฉันชอบสิ่งนี้ไม่ต้องใช้ไลบรารีเพิ่มเติมหรือพึ่งพาฝั่งเซิร์ฟเวอร์เมื่อคุณไม่มีความหรูหรา แรงบันดาลใจจากคุณ แต่ในองค์ประกอบของชั้นฉันทำ componentDidMount() { this.message.current.innerHTML = this.state.selectedMessage.body; }ร่างกายเป็น html ที่หลบหนีสำหรับฉัน
webhound

2

ในกรณีของฉันฉันใช้react-render-html

ก่อนติดตั้งแพคเกจโดย npm i --save react-render-html

แล้ว

import renderHTML from 'react-render-html';

renderHTML("<a class='github' href='https://github.com'><b>GitHub</b></a>")

1

ฉันไม่สามารถรับการทำงานร่วมกับnpm build react-html-parserอย่างไรก็ตามในกรณีของฉันฉันสามารถใช้https://reactjs.org/docs/fragments.htmlได้สำเร็จ ฉันมีความต้องการที่จะแสดงอักขระยูนิโค้ด html ไม่กี่ตัว แต่ไม่ควรฝังใน JSX โดยตรง ภายใน JSX จะต้องเลือกจากสถานะของคอมโพเนนต์ ตัวอย่างรหัสส่วนประกอบได้รับด้านล่าง:

constructor() 
{
this.state = {
      rankMap : {"5" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9733;</Fragment> , 
                 "4" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9734;</Fragment>, 
                 "3" : <Fragment>&#9733; &#9733; &#9733; &#9734; &#9734;</Fragment> , 
                 "2" : <Fragment>&#9733; &#9733; &#9734; &#9734; &#9734;</Fragment>, 
                 "1" : <Fragment>&#9733; &#9734; &#9734; &#9734; &#9734;</Fragment>}
                };
}

render() 
{
       return (<div class="card-footer">
                    <small class="text-muted">{ this.state.rankMap["5"] }</small>
               </div>);
}


-2

หากคุณมีการควบคุม {this.props.match.description} และหากคุณใช้ JSX ฉันอยากจะแนะนำไม่ให้ใช้ "dangerlySetInnerHTML"

// In JSX, you can define a html object rather than a string to contain raw HTML
let description = <h1>Hi there!</h1>;

// Here is how you print
return (
    {description}
);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.