Как я могу вставить компонент React в строку HTML, а затем визуализировать его с опасно SetInner HTML? - PullRequest
0 голосов
/ 29 апреля 2020

Я использую Next Js. У меня есть строка 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}}
   />
   ...
)

As you can see, the resulting html is the same as using the Zoom component as intended, but the button loses its event

Как видно на изображении, результирующий html такой же, как при использовании компонента Zoom, как и предполагалось, но кнопка теряет свое событие

Итак, как мне объединить строку html с сервера и неконтролируемый компонент Zoom для достижения того, что я хочу?

1 Ответ

0 голосов
/ 30 апреля 2020

Благодаря ответу Уильяма в комментариях я получил это решение

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