Kết xuất chuỗi HTML dưới dạng HTML thực trong thành phần React


159

Đây là những gì tôi đã cố gắng và làm thế nào nó đi sai.

Những công việc này:

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

Đây không phải là:

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

Thuộc tính mô tả chỉ là một chuỗi nội dung HTML bình thường. Tuy nhiên, nó được kết xuất dưới dạng một chuỗi, không phải là HTML vì một số lý do.

nhập mô tả hình ảnh ở đây

Bất kỳ đề xuất?

Câu trả lời:


50

Kiểm tra xem văn bản bạn đang cố nối vào nút không được thoát như thế này:

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

Thay vì điều này:

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

nếu được thoát, bạn nên chuyển đổi nó từ phía máy chủ của bạn.

Nút là văn bản vì được thoát

Nút là văn bản vì được thoát

Nút là một nút dom vì không thoát được

Nút là một nút dom vì không thoát được


3
Đây là vấn đề. Chuỗi mô tả đã thoát HTML. Tôi đã bỏ qua nó và bây giờ nó hoạt động tốt.
Sergio Tapia

4
Vui lòng tránh sử dụng dangerouslySetInnerHTMLthay vì sử dụng Fragmenttừ phản ứng v16. Kiểm tra câu trả lời tiếp theo của @ brad-adams
Kunal Parekh

2
Đánh giá cao đề cập đến @KunalParekh, nhưng chúng là những thứ khác nhau. Câu trả lời của tôi chỉ hợp lệ nếu html nằm trong ứng dụng của bạn (nghĩa là nó thực sự là JSX). Để phân tích HTML từ nguồn bên ngoài sang jsx, bạn cần tìm giải pháp khác.
Brad Adams

113

Liệu this.props.match.descriptioncó phải là một chuỗi hoặc một đối tượng? Nếu đó là một chuỗi, nó sẽ được chuyển đổi thành HTML. Thí dụ:

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

Kết quả: http://codepen.io/ilanus/pen/QKgoLA?editors=1011

Tuy nhiên nếu description: <h1 style="color:red;">something</h1>không có trích dẫn ''bạn sẽ nhận được:

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

Nếu đó là một chuỗi và bạn không thấy bất kỳ đánh dấu HTML nào, vấn đề duy nhất tôi thấy là đánh dấu sai ..

CẬP NHẬT

Nếu bạn đang làm việc với HTMLEntitle. Bạn cần giải mã chúng trước khi gửi chúng đếndangerouslySetInnerHTML đó là lý do tại sao chúng gọi nó là nguy hiểm :)

Ví dụ làm việc:

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.descriptionlà một chuỗi, không phải là một đối tượng. Bạn có ý nghĩa gì với đánh dấu sai? Bạn có nghĩa là các thẻ không được tiết lộ? Phản ứng chỉ nên làm cho nó không?
Sergio Tapia

Bạn có thể dán vào đây console.log (this.props.match.description);
Ilanus

Một ví dụ:&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;
Sergio Tapia

Trong trường hợp này, bạn cần sử dụng .innerHTML hoặc giải mã HTMLEntities.
Ilanus

Trả về nhiều dòng hoặc mã HTML với các thẻ: function htmlDecode (input) {var e = document.createEuity ('div'); e.innerHTML = đầu vào; var returnString = ''; for (index = 0; index <e.childNodes.length; index ++) {// trường hợp chỉ là một chuỗi if (e.childNodes [index] .nodeValue) {returnString + = e.childNodes [index] .nodeValue; } // trường hợp HTML if (e.childNodes [index] .outerHTML) {returnString + = e.childNodes [index] .outerHTML; }} return returnString; }
Chris Adams

58

Tôi sử dụng 'Reac-html-Parser'

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

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

Nguồn trên npmjs.com

Nâng lên nhận xét của @ okram để dễ nhìn hơn:

từ mô tả github của nó: Chuyển đổi các chuỗi HTML trực tiếp thành các thành phần React tránh sự cần thiết phải sử dụng một cách nguy hiểm SetInnerHTML từ npmjs.com Một tiện ích để chuyển đổi các chuỗi HTML thành các thành phần React. Tránh sử dụng một cách nguy hiểm SetInnerHTML và chuyển đổi các thành phần, thuộc tính và kiểu nội tuyến HTML tiêu chuẩn thành tương đương React của chúng.


11
Thư viện này có sử dụng "risklyInInHTMLHTML" trong nền không?
Omar

1
từ mô tả github của nó: Converts HTML strings directly into React components avoiding the need to use dangerouslySetInnerHTMLtừ 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

Nếu bạn có quyền kiểm soát nơi chuỗi chứa html đến từ đâu (nghĩa là ở đâu đó trong ứng dụng của bạn), bạn có thể hưởng lợi từ <Fragment>API mới , thực hiện một số việc như:

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
Không có chuỗi chứa html trong ví dụ của bạn. Đó là jsx hoặc chuỗi đơn giản.
mrkvon

3
Vâng, về mặt kỹ thuật, bạn đúng @mrkvon, tuy nhiên như tôi đã đề cập, giải pháp này chỉ hợp lệ nếu nói "html" / jsx là thứ bạn có quyền kiểm soát. Ví dụ, không phải để hiển thị một số html thô được cung cấp qua API. Trước FragmentAPI, nó luôn là một nỗi đau đối với tôi, điều đó đòi hỏi các spankết thúc tốt đẹp đôi khi sẽ gây rối với bố cục flex. Khi tôi vấp phải câu hỏi này để tìm kiếm một giải pháp khả thi, tôi nghĩ tôi sẽ chia sẻ cách tôi giải quyết mọi thứ.
Brad Adams

2
Cảm ơn! Đây là giải pháp duy nhất hoạt động trong trường hợp của tôi. Ngoài ra, trả lời bình luận của mrkvon về câu trả lời này: Câu trả lời này thực sự có chứa html tức là Some text <strong>wrapped with strong</strong>chứa thẻ html strong.
Binita Bharati

@BinitaBharati Nhưng đó không phải là một chuỗi. Nếu bạn nhận được một chuỗi từ API như "<p> Đây là Chuỗi </ p>" (hoặc đơn giản là lưu trữ một chuỗi trong một biến), khi bạn đặt chuỗi này vào <Fragment>, đầu ra vẫn sẽ chứa < p> thẻ.
Ngày

1
@BradAdams. Mặc dù vậy, mẹo hay. Tôi có thể thấy các trường hợp nơi nó trở nên tiện dụng.
Ngày

6

Bạn chỉ cần sử dụng phương pháp ReactnerHTML nguy hiểm

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

Hoặc bạn có thể thực hiện nhiều hơn với cách dễ dàng này: Kết xuất HTML thô trong ứng dụng React


5

nguy hiểm SetInnerHTML

nguy hiểm SetInnerHTML là sự thay thế của React để sử dụng InternalHTML trong DOM trình duyệt. Nói chung, việc thiết lập HTML từ mã rất rủi ro vì việc vô tình khiến người dùng của bạn gặp phải một cuộc tấn công kịch bản chéo trang (XSS). Vì vậy, bạn có thể đặt HTML trực tiếp từ React, nhưng bạn phải gõ nguy hiểm SetInnerHTML và truyền một đối tượng bằng khóa __html, để tự nhắc nhở bản thân rằng nó nguy hiểm. Ví dụ:

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

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

3

Tôi sử dụng InternalHTML cùng với một tham chiếu để mở rộng:

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

Tôi thích điều này, không cần thêm thư viện hoặc phụ thuộc vào phía máy chủ khi bạn không có sự sang trọng đó. Lấy cảm hứng từ bạn, nhưng trong một thành phần lớp tôi đã làm componentDidMount() { this.message.current.innerHTML = this.state.selectedMessage.body; }cơ thể là html thoát cho tôi.
webhound

2

Trong trường hợp của tôi, tôi đã sử dụng Reac-render-html

Đầu tiên cài đặt gói bằng cách npm i --save react-render-html

sau đó,

import renderHTML from 'react-render-html';

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

1

Tôi không thể npm buildlàm việc với react-html-parser. Tuy nhiên, trong trường hợp của tôi, tôi đã có thể sử dụng thành công https://reactjs.org/docs/fragments.html . Tôi đã có một yêu cầu để hiển thị một vài ký tự unicode html, nhưng chúng không nên được nhúng trực tiếp vào JSX. Trong JSX, nó phải được chọn từ trạng thái của Thành phần. Đoạn mã thành phần được đưa ra dưới đây:

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

Nếu bạn có quyền kiểm soát {this.props.match.description} và nếu bạn đang sử dụng JSX. Tôi khuyên bạn không nên sử dụng "nguy hiểm SetInnerHTML".

// 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}
);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.