React.js: ตั้งค่า innerHTML เทียบกับ harmlySetInnerHTML


171

มี "เบื้องหลัง" ความแตกต่างจากการตั้งค่า innerHTML ขององค์ประกอบหรือการตั้งค่าคุณสมบัติ harmlySetInnerHTML บนองค์ประกอบหรือไม่ สมมติว่าฉันทำความสะอาดสิ่งต่าง ๆ ให้ถูกต้องเพื่อความเรียบง่าย

ตัวอย่าง:

var test = React.createClass({
  render: function(){
    return (
      <div contentEditable='true' dangerouslySetInnerHTML={{ __html: "Hello" }}></div>
    );
  }
});

VS

var test = React.createClass({
  componentDidUpdate: function(prevProp, prevState){
    this.refs.test.innerHTML = "Hello";
  },
  render: function(){
    return (
      <div contentEditable='true' ref='test'></div>
    );
  }
});

ฉันกำลังทำอะไรที่ซับซ้อนกว่าตัวอย่างด้านบนเล็กน้อย แต่แนวคิดโดยรวมเหมือนกัน

คำตอบ:


237

ใช่มีความแตกต่าง!

ผลทันทีของการใช้innerHTMLกับdangerouslySetInnerHTMLเหมือนกัน - โหนด DOM จะอัปเดตด้วย HTML ที่ถูกแทรก

อย่างไรก็ตามเบื้องหลังเมื่อคุณใช้dangerouslySetInnerHTMLมันจะทำให้ React รู้ว่า HTML ที่อยู่ในองค์ประกอบนั้นไม่ใช่สิ่งที่ใส่ใจ

เนื่องจาก React ใช้ DOM เสมือนเมื่อไปเปรียบเทียบ diff กับ DOM จริงมันสามารถทำการเลี่ยงผ่านการตรวจสอบ children ของโหนดนั้นได้โดยตรงเนื่องจากรู้ว่า HTML นั้นมาจากแหล่งอื่นจะมาจากแหล่งอื่น ดังนั้นจึงมีประสิทธิภาพเพิ่มขึ้น

ที่สำคัญถ้าคุณใช้เพียงแค่innerHTMLReact ก็ไม่มีทางที่จะรู้ว่าโหนด DOM นั้นได้รับการแก้ไข ครั้งต่อไปที่renderเรียกใช้ฟังก์ชันReact จะเขียนทับเนื้อหาที่ถูกแทรกด้วยตนเองด้วยสิ่งที่คิดว่าสถานะที่ถูกต้องของโหนด DOM นั้นควรเป็น

โซลูชันของคุณที่ใช้componentDidUpdateเพื่อให้แน่ใจว่าเนื้อหาตรงกันเสมอฉันเชื่อว่าใช้งานได้ แต่อาจมีการกะพริบระหว่างการแสดงผลแต่ละครั้ง


11
ฉันเขียนการทดสอบ perf ขนาดเล็กที่ไม่ใช่ทางวิทยาศาสตร์เพื่อแสดงความแตกต่างระหว่างการฝัง SVG และการใช้dangerouslySetInnerHTML: webpackbin.com/bins/-KepHa-AMxQgGxOUnAac - ปรับวิธีการ innerHTML เกือบสองเท่า (ดูคอนโซลใน webpackbin)
Joscha

4
นั่นเป็นเรื่องจริงและง่ายต่อการคาดเดา เนื่องจาก innerHTML เป็นวิธีเนทีฟที่ผูกโค้ด SVG โดยตรงกับ DOM โดยไม่พิจารณาอะไรเลย dangerlySetInnerHTML นั้นเป็นวิธีที่มาจาก React ที่จะต้องมีการแยกวิเคราะห์รหัส SVG ในฐานะเด็ก ๆ ในส่วน React Component ก่อนที่จะวางไว้ใน DOM เสมือนและจากนั้นแสดงเป็น DOM
Up209d

3

ตามที่อันตรายชุด innerHTML ,

การใช้innerHTMLกระป๋องที่ไม่เหมาะสมเปิดให้คุณมากถึง a โจมตีข้ามสคริปต์ (XSS) การฆ่าเชื้ออินพุตของผู้ใช้สำหรับการแสดงผลนั้นมีแนวโน้มที่จะเกิดข้อผิดพลาดได้ง่ายและความล้มเหลวในการฆ่าเชื้ออย่างถูกต้องเป็นหนึ่งในสาเหตุสำคัญของช่องโหว่ของเว็บบนอินเทอร์เน็ต

ปรัชญาการออกแบบของเราคือมันควรจะ "ง่าย" ในการทำให้สิ่งต่าง ๆ ปลอดภัยและนักพัฒนาควรระบุเจตนาของพวกเขาอย่างชัดเจนเมื่อดำเนินการ "ไม่ปลอดภัย" ชื่อเสาdangerouslySetInnerHTMLถูกเลือกโดยเจตนาให้น่ากลัวและสามารถใช้ค่า prop (วัตถุแทนสตริง) เพื่อระบุข้อมูลที่ถูกสุขลักษณะ

หลังจากทำความเข้าใจเกี่ยวกับการรักษาความปลอดภัยอย่างสมบูรณ์และล้างข้อมูลให้ถูกต้องแล้วให้สร้างวัตถุใหม่ที่มีเฉพาะคีย์ __htmlและข้อมูลที่ถูกสุขอนามัยของคุณเป็นค่า นี่คือตัวอย่างการใช้ไวยากรณ์ JSX:

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

<div dangerouslySetInnerHTML={createMarkup()} /> 

อ่านเพิ่มเติมเกี่ยวกับมันโดยใช้ลิงค์ด้านล่าง:

เอกสาร : React DOM Elements - dangerouslySetInnerHTML


1
สิ่งนี้ไม่ตอบคำถาม
เควนติน

2

ขึ้นอยู่กับ ( dangerlySetInnerHTML )

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


1
ตามเอกสารดูเหมือนว่านี่เป็นเหตุผลเดียวที่ยังคงสับสน
mkb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.