2

At the top of my gatsby blog (a react component) I have a function that gets a url's extension, and based on whether it's an image or a video it returns a line of html like so:

  const printPicOrVid = function(myUrl) {
    let fileExt =
      myUrl.substring(myUrl.lastIndexOf(".") + 1, myUrl.length) || myUrl
    if (fileExt === "jpg" || fileExt === "png" || fileExt === "gif") {
      return '<img src="https:' + myUrl + '" />'
    } else if (fileExt === "mp4") {
      return '<video src="https:' + myUrl + '"></video>'
    }
  }

which successfully returns a string of something like <img src="https://contentful.com/whatever/image.jpg" />

in my return part of the react page I have:

{edge.node.heroImage && printPicOrVid(edge.node.heroImage.file.url)}

which is saying: if the heroImage from contentful exists, then return the jpg or mp4 html. The problem is, I just get a string of the HTML printed to the page, not the html rendering an actual image or video like intended.

have a feeling the answer here is dangerously set inner HTML, but not sure how to implement. Any help much appreciated, thanks.

Ismael Padilla
  • 5,246
  • 4
  • 23
  • 35
StephD
  • 266
  • 3
  • 20
  • 2
    Actually yeah, Ismael's is a better idea. Just return the JSX img or video element, and make the `src` the dynamic string, rather than the whole element a string – Jayce444 Jan 22 '20 at 00:00

2 Answers2

5

When returning JSX in a function, you should just plainly return the JSX element you want. So you'd write return <div/> instead of return '<div/>'. So:

return '<img src="https:' + myUrl + '" />'

Should be

return <img src={"https:" + myUrl} />

Otherwise you'd return a string instead of JSX. Same in the other return statement, which should be:

return <video src={"https:" + myUrl}></video>
Ismael Padilla
  • 5,246
  • 4
  • 23
  • 35
2

You need to return a <div /> with attribute dangerouslySetInnerHTML set to {{ __html: printPicOrVid(edge.node.heroImage.file.url) }}.

Full code:

{edge.node.heroImage && <div dangerouslySetInnerHTML={{ __html: printPicOrVid(edge.node.heroImage.file.url) }} />}
Cristian Torres
  • 256
  • 3
  • 12
  • 1
    Thank you! I figured I should avoid dangerouslySetInnerHTML if possible though so I went with Ismael's solution, appreciate the answer though. – StephD Jan 22 '20 at 00:12