首页 > 解决方案 > 如何在 HTML 字符串中插入一个 React 组件,然后使用 dangerouslySetInnerHTML 渲染它?

问题描述

我正在使用 NextJs。我有一个从服务器获取的 html 字符串。它代表一篇博文并包含多个<img>标签。我目前正在渲染这样的帖子:

const blogpostHtml = "..." // an html string that comes from the server
return (
  ...
  <div
    dangerouslySetInnerHTML={{__html: blogpostHtml}}
  />
  ...
)

它工作正常。但是,我想为图像添加功能。我发现这个库用一个不受控制的组件完成了我想要的:

  ...
  <Zoom>
    <img
      alt="some alt"
      width="500"
      src="the image url"
    />
  </Zoom>
  ...

但是,我注意到我不能简单地插入Zoom标签,因为它被解释为原始 html 标签而不是组件。如果我尝试将它呈现为字符串,它就会失去功能。

let html = ReactDOMServer.renderToString(
  <Zoom>
    <img
      alt="some alt"
      width="500"
      src="the image url"
     />
   </Zoom>
 )

 return (
   ...
   <div
     dangerouslySetInnerHTML={{__html: html}}
   />
   ...
)

如您所见,生成的 html 与按预期使用 Zoom 组件相同,但按钮丢失了其事件

正如您在图像中看到的,生成的 html 与按预期使用 Zoom 组件相同,但按钮丢失了它的事件

那么如何将来自服务器的 html 字符串和不受控制的 Zoom 组件结合起来来实现我想要的呢?

标签: reactjsnext.js

解决方案


感谢威廉在评论中的回答,我得到了这个解决方案

import Zoom from 'react-medium-image-zoom'
import ReactDOM from 'react-dom'
import { useEffect } from 'react'

  const Index = () => {
   const html = ` 
   <p>This is some text</p>
     <img src="some-img-src.jpg"/>
   <p>More text here</p>
   `

   useEffect(() => {
     // 1. extract imgs and src
     const imgs = document.getElementsByTagName('img')
     const srcArray = Array.from(imgs).map(img => img.src)

     // 2. wrap images with div then replace each div using ReactDOM.render
     for (let i = 0; i < imgs.length; i++) {
       const wrapper = document.createElement('div')
       wrapper.setAttribute('id', `img-${i}`)

       imgs[i].parentNode.insertBefore(wrapper, imgs[i])
       wrapper.appendChild(imgs[i])

       ReactDOM.render(
         <Zoom>
           <img src={srcArray[i]} />
         </Zoom>,
         document.querySelector(`#img-${i}`)
       )   
     }   
   }, []) 

    return (
     <>  
        <div
          dangerouslySetInnerHTML={{
            __html: html
          }}  
        />
      </> 
    )
  }

  export default Index

推荐阅读