graphQL + gatsby: query a field that is Image or mp4

Viewed 337

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?

2 Answers

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} />
)}

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.

Related