3

Have a gatsby blog to which I've added a cover image that is either an image (I want that to appear as a Gatsby Image) or mp4 (I want that to appear as html5 video).

The problem is, when I query this field (in my markdown posts, cover: x.mp4 or cover: x.jpg), if it's an mp4 and it doesn't have a property of childImageSharp (error: TypeError: Cannot read property 'fluid' of null).

My query looks like this:

  frontmatter {
    date(formatString: "YYYY")
    title
    cover {
      childImageSharp {
        fluid(maxWidth: 900) {
          ...GatsbyImageSharpFluid_noBase64
          ...GatsbyImageSharpFluidLimitPresentationSize
        }
      }
    }
  }

so my goal is to have some kind of JSX like:

{post.frontmatter.cover.childImageSharp && (
  <Img fluid={post.frontmatter.cover.childImageSharp.fluid} />
)}
{post.frontmatter.cover.childImageSharp ? '' : (
  <video src={post.frontmatter.cover} />
)}

any ideas?

StephD
  • 266
  • 3
  • 20

2 Answers2

2

The problem is, when I query this field (in my markdown posts, cover: x.mp4 or cover: x.jpg), if it's an mp4 and it doesn't have a property of childImageSharp (error: TypeError: Cannot read property 'fluid' of null).

The cover field will be a File node, so you won't be able to get the video src from it directly. If you just want access to the mp4 file (to put inside a video tag), you can query for its publicURL:

  frontmatter {
    date(formatString: "YYYY")
    title
    cover {
      extension
      publicURL

      childImageSharp {
        fluid(maxWidth: 900) {
          ...GatsbyImageSharpFluid_noBase64
          ...GatsbyImageSharpFluidLimitPresentationSize
        }
      }
    }
  }

Then in your component:

{cover.extension === 'mp4'
  ? <video src={cover.publicURL} />
  : <Img fluid={cover.childImageSharp.fluid} />
)}
Derek Nguyen
  • 11,294
  • 1
  • 40
  • 64
  • AH it works!!! Thanks so much! I'm not great at graphQL so I wasn't sure what the properties on cover could be. Thank you. – StephD May 23 '20 at 18:12
1

Why you don't mix both methods?

{post.frontmatter.cover.childImageSharp ? <Img fluid={post.frontmatter.cover.childImageSharp.fluid} /> : <video src={post.frontmatter.cover} />}

Regardless of how you will manage it, I think that your idea is a good approach to achieve what you want. You'll render one component or another depending on your query so, it's efficient and clean.

Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67