Merender html mentah dengan reactjs

154

Jadi apakah ini satu-satunya cara untuk membuat html mentah dengan reactjs?

// http://facebook.github.io/react/docs/tutorial.html
// tutorial7.js
var converter = new Showdown.converter();
var Comment = React.createClass({
  render: function() {
    var rawMarkup = converter.makeHtml(this.props.children.toString());
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={{__html: rawMarkup}} />
      </div>
    );
  }
});

Saya tahu ada beberapa cara keren untuk menandai barang dengan JSX, tapi saya terutama tertarik untuk dapat membuat html mentah (dengan semua kelas, gaya inline, dll.). Sesuatu yang rumit seperti ini:

<!-- http://getbootstrap.com/components/#dropdowns-example -->
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>

Saya tidak ingin harus menulis ulang semua itu di BEJ.

Mungkin saya salah memikirkan semua ini. Tolong perbaiki saya.

vinhboy
sumber
1
Itu hampir BEJ. Jika Anda merender banyak markup sebagai HTML mentah, Anda kehilangan manfaat menggunakan perpustakaan seperti Bereaksi. Saya akan merekomendasikan melakukan perubahan kecil (seperti "class" -> "className") untuk membiarkan Bereaksi menangani elemen.
Ross Allen
2
Untuk contoh khusus ini seseorang telah melakukan pekerjaan untuk Anda , namun pertanyaannya masih berlaku untuk kasus umum.
Randy Morris

Jawaban:

43

Anda dapat memanfaatkan html-to-reactmodul npm.

Catatan: Saya penulis modul dan baru saja menerbitkannya beberapa jam yang lalu. Silakan melaporkan masalah bug atau kegunaan.

Mike Nikles
sumber
24
apakah itu menggunakan hazardallySetInnerHTML secara internal?
Yash Sharma
2
Saya baru saja memeriksa kodenya. Tampaknya tidak menggunakan berbahayaSetInnerHTML.
Ajay Raghav
Mike apakah Anda masih aktif mempertahankan modul npm ini?
Daniel
Hai Daniel, saya tidak melakukannya dan salah satu kontributor mengambil alih dan menerbitkan rilis terakhir 7 bulan lalu. Lihat github.com/aknuds1/html-to-react
Mike
Ini tidak menggunakanSetInnerHTML berbahaya.
Tessaracter
185

Sekarang ada metode yang lebih aman untuk membuat HTML. Saya membahas hal ini dalam jawaban sebelumnya di sini . Anda memiliki 4 opsi, penggunaan terakhir dangerouslySetInnerHTML.

Metode rendering HTML

  1. Paling mudah - Gunakan Unicode, simpan file sebagai UTF-8 dan atur charsetke UTF-8.

    <div>{'First · Second'}</div>

  2. Aman - Gunakan nomor Unicode untuk entitas di dalam string Javascript.

    <div>{'First \u00b7 Second'}</div>

    atau

    <div>{'First ' + String.fromCharCode(183) + ' Second'}</div>

  3. Atau array campuran dengan elemen string dan JSX.

    <div>{['First ', <span>&middot;</span>, ' Second']}</div>

  4. Last Resort - Masukkan HTML mentah menggunakan dangerouslySetInnerHTML.

    <div dangerouslySetInnerHTML={{__html: 'First &middot; Second'}} />

Brett DeWoody
sumber
Yang saya butuhkan adalah 3 atau 4
Nicolas S.Xu
bertanya-tanya apa yang diterima atribut lain dangerouslySetInnerHTMLselain __html
Juan Solano
30
Saya suka utas ini ... Secara implisit: "Lakukan apa pun yang Anda bisa untuk tidak menggunakan # 4". Semua orang: "# 4 bekerja dengan sangat baik!"
deepelement
1
@JuanSolano tidak ada, sesuai dengan entri lengkapi otomatis dalam lingkungan TypeScript.
Andreas Linnert
Dalam pertanyaan serupa, stackoverflow.com/questions/19266197/… , jawaban ini tidak terlalu bagus. Mungkin lebih cocok untuk pertanyaan ini atau mungkin orang tidak membaca jawabannya ...: D
425nesp
27

Saya telah menggunakan ini dalam situasi yang cepat dan kotor:

// react render method:

render() {
    return (
      <div>
        { this.props.textOrHtml.indexOf('</') !== -1
            ? (
                <div dangerouslySetInnerHTML={{__html: this.props.textOrHtml.replace(/(<? *script)/gi, 'illegalscript')}} >
                </div>
              )
            : this.props.textOrHtml
          }

      </div>
      )
  }
Cory Robinson
sumber
7
Ini tidak aman - bagaimana jika HTML berisi <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" onload="alert('test');">?
yjwong
11
Aman jika Anda mengendalikan HTML yang dirender
John
18

Saya sudah mencoba komponen murni ini:

const RawHTML = ({children, className = ""}) => 
<div className={className}
  dangerouslySetInnerHTML={{ __html: children.replace(/\n/g, '<br />')}} />

fitur

  • Dibawa classNameprop (lebih mudah untuk bergaya)
  • Mengganti \nke <br />(Anda sering ingin melakukan itu)
  • Tempatkan konten sebagai anak - anak ketika menggunakan komponen seperti:
  • <RawHTML>{myHTML}</RawHTML>

Saya telah menempatkan komponen dalam Gist di Github: RawHTML: komponen murni ReactJS untuk membuat HTML

Netsi1964
sumber
12
export class ModalBody extends Component{
    rawMarkup(){
        var rawMarkup = this.props.content
        return { __html: rawMarkup };
    }
    render(){
        return(
                <div className="modal-body">
                     <span dangerouslySetInnerHTML={this.rawMarkup()} />

                </div>
            )
    }
}
Jozcar
sumber
Pekerjaan di atas bagi saya, saya melewatkan html ke modal tubuh.
Jozcar
12

dangerouslySetInnerHTML adalah Bereaksi pengganti untuk menggunakan innerHTML di DOM browser. Secara umum, pengaturan HTML dari kode berisiko karena mudah untuk secara tidak sengaja mengekspos pengguna Anda terhadap serangan lintas situs (XSS).

Lebih baik / lebih aman untuk membersihkan HTML mentah Anda (menggunakan misalnya, DOMPurify) sebelum menyuntikkannya ke DOM via dangerouslySetInnerHTML.

DOMPurify - pembersih XSS hanya DOM, super cepat, tahan uber untuk HTML, MathML, dan SVG. DOMPurify berfungsi dengan default yang aman, tetapi menawarkan banyak konfigurasi dan pengait.

Contoh :

import React from 'react'
import createDOMPurify from 'dompurify'
import { JSDOM } from 'jsdom'

const window = (new JSDOM('')).window
const DOMPurify = createDOMPurify(window)

const rawHTML = `
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>
`

const YourComponent = () => (
  <div>
    { <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(rawHTML) }} /> }
  </div>
)

export default YourComponent
Yuci
sumber
Inilah yang saya cari dalam jawaban ini. Seharusnya memiliki lebih banyak
suara positif
6

Saya menggunakan perpustakaan ini yang disebut Parser . Itu bekerja untuk apa yang saya butuhkan.

import React, { Component } from 'react';    
import Parser from 'html-react-parser';

class MyComponent extends Component {
  render() {
    <div>{Parser(this.state.message)}</div>
  }
};
ecairol
sumber
3
21KB (8KB di-gzip). Saya tidak bisa membenarkan itu untuk kode browser.
Peter Bengtsson
perpustakaan ini memecah aplikasi Expo saya
ekkis
5

dangerouslySetInnerHTMLtidak boleh digunakan kecuali benar-benar diperlukan. Menurut dokumen, "Ini terutama untuk bekerja sama dengan perpustakaan manipulasi string DOM" . Ketika Anda menggunakannya, Anda melepaskan manfaat dari manajemen DOM React.

Dalam kasus Anda, cukup mudah untuk mengkonversi ke sintaks JSX yang valid; cukup ubah classatribut menjadi className. Atau, seperti yang disebutkan dalam komentar di atas, Anda dapat menggunakan perpustakaan ReactBootstrap yang merangkum elemen Bootstrap ke dalam komponen Bereaksi.

Breno Ferreira
sumber
8
Terima kasih atas jawaban anda. Saya memahami implikasi keamanan menggunakan innerHTML dan saya tahu saya bisa mengubahnya menjadi JSX. Tetapi saya secara khusus bertanya tentang dukungan React untuk menggunakan cuplikan HTML mentah.
vinhboy
Apa sebenarnya yang Anda maksud dengan "Bereaksi dukungan untuk menggunakan potongan HTML mentah"?
Breno Ferreira
2

Ini adalah versi yang sedikit kurang dipuji dari fungsi RawHTML yang diposting sebelumnya. Ini memungkinkan Anda:

  • konfigurasikan tag
  • opsional ganti baris ke <br />'s
  • lulus alat peraga tambahan yang RawHTML akan berikan ke elemen yang dibuat
  • berikan string kosong ( RawHTML></RawHTML>)

Inilah komponennya:

const RawHTML = ({ children, tag = 'div', nl2br = true, ...rest }) =>
    React.createElement(tag, {
        dangerouslySetInnerHTML: {
            __html: nl2br
                ? children && children.replace(/\n/g, '<br />')
                : children,
        },
        ...rest,
    });
RawHTML.propTypes = {
    children: PropTypes.string,
    nl2br: PropTypes.bool,
    tag: PropTypes.string,
};

Pemakaian:

<RawHTML>{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2">{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2" className="test">{'First &middot; Second'}</RawHTML>
<RawHTML>{'first line\nsecond line'}</RawHTML>
<RawHTML nl2br={false}>{'first line\nsecond line'}</RawHTML>
<RawHTML></RawHTML>

Keluaran:

<div>First · Second</div>
<h2>First · Second</h2>
<h2 class="test">First · Second</h2>
<div>first line<br>second line</div>
<div>first line
second line</div>
<div></div>

Itu akan pecah pada:

<RawHTML><h1>First &middot; Second</h1></RawHTML>
Christiaan Westerbeek
sumber
0

Saya perlu menggunakan tautan dengan atribut onLoad di kepala saya di mana div tidak diizinkan sehingga ini membuat saya sangat kesakitan. Solusi saya saat ini adalah menutup tag skrip asli, melakukan apa yang perlu saya lakukan, lalu membuka tag skrip (ditutup oleh yang asli). Semoga ini bisa membantu seseorang yang sama sekali tidak punya pilihan lain:

<script dangerouslySetInnerHTML={{ __html: `</script>
   <link rel="preload" href="https://fonts.googleapis.com/css?family=Open+Sans" as="style" onLoad="this.onload=null;this.rel='stylesheet'" crossOrigin="anonymous"/>
<script>`,}}/>
Adam Lane
sumber