Search code examples
javascriptreactjsgatsbygatsby-imagereact-dom-server

Injecting gatsby-image into html created from markdown using ReactDOMServer.renderToString


Minimum Reproducible Example on Github


I'm trying to inject some images into my pages created from markdown. I'm trying to do this using ReactDomServer.renderToString()

const componentCreatedFromMarkdown = ({data}) => {
...    
    useEffect(() => {
        const injectDivs = Array.from(document.getElementsByClassName('injectDivs'))
        injectDivs.forEach((aDiv) => {
            aDiv.innerHTML = ReactDOMServer.renderToString(<Img fluid={data.allFile.edges[0].node.childImageSharp.fluid} />)
        }
    })
...
}

The img is showing as a black box, if I right click the image I can open it in a new tab, which shows the image as it is supposed to be.


enter image description here


Solution

  • How I understand the problem

    • The image html is correctly inserted into the page

    • gatsby-image loads the lowest quality image and applies some inline styles. All that information is present in the html) This is done to enable the blur-up effect on the image for a better UX.

    • The client side code that would load a higher resolution image and remove the inline styles is never applied.

    Useful diagnostic information

    • The function inside useEffect does not get run on the server-side, but rather on the client after the component has mounted. It's possible to verify this by adding a console.log statement inside the effect and seeing that it is logged on the browser's console.

    Source of the problem

    • ReactDOMServer.renderToString() only builds the HTML that's required by a component, it then requires the component to be hydrated.

    Direct fix

    • You can use ReactDOM.render to put the image on the page, given that the effect will execute client side. I have a PR showing that here.

    Recommended approach

    Hope that helps! 😄