Structured Text: How to render different blocks?

Hey DatoCMS crew!

Context

I’m migrating from Modular Content Fields to Structured Text Fields for my Gatsby blog, using the example Github repo as my guide.

Goal

To render different blocks used within a Structured Text Field.

The two different blocks are as follows

  • Image: returns <GatsbyImage src={record.image.gatsbyImageData}/>
  • External Embed: returns <div>{record.video.url}</div>

Problem

When viewing one of my blog posts with just text and image blocks, everything works. However, when I view a blog post with text, image and external embed blocks, the following error occurs.

One unhandled runtime error found in your files. See the list below to fix it:
Error in function renderBlock in ./src/components/post-body.tsx:15
record.image is null

Here are the contents of post-body minus the imports.

export default function PostBody({ content }) {
  return (
    <section className="post">
      <StructuredText
        data={content}
        renderBlock={({ record }) => {
          switch (record.__typename) {
            case "DatoCmsVisual":
              return (
                <div className="post__visual">
                  <GatsbyImage image={record.image.gatsbyImageData} />
                </div>
              )
            case "DatoCmsExternalEmbed":
              return <div className="post__visual">{record.externalVideo.url}</div>
            default:
              return (
                <>
                  <p>Don't know how to render a block!</p>
                  <pre>{JSON.stringify(record, null, 2)}</pre>
                </>
              )
          }
        }}
      />
    </section>
  )
}

I suspect the PostBody function isn’t the problem here, rather my lack of understanding how to query multiple blocks within Structured Text. Here is the query which I use to render the contents of each post.

export const pageQuery = graphql`
  query ($slug: String!) {
    site: datoCmsSite {
      favicon: faviconMetaTags {
        ...GatsbyDatoCmsFaviconMetaTags
      }
    }
    post: datoCmsPostNext(slug: { eq: $slug }) {
      coverImage {
        alt
        gatsbyImageData(width: 1500)
      }
      title
      summary
      date(formatString: "MMMM DD, YYYY")
      content {
        value
        blocks {
          __typename
          id: originalId
          image {
            alt
            gatsbyImageData(width: 1500)
          }
          externalVideo {
            src
          }
        }
      }
      slug
      seo: seoMetaTags {
        ...GatsbyDatoCmsSeoMetaTags
      }
    }
  }
`

I suspect this is something basic, but any help would be greatly appreciated.

Links

Hello @jessebox

It seems like the issue is that the field “image” inside your ‘visual’ block is not a required field, meaning that this block can exist with a null value on this field.
When this happens, and you try to access gatsbyImageData from the null field, you get the error
So the way to go here would be to make that field a required field on your block, and make sure that in all already existing blocks, this field has a value.

Hope this helps!

Hey mate, thanks for the tip!

I’ve made the change you suggested, and double-checked that there are no visual blocks with empty images fields.

Unfortunately, I can’t verify if that solved the initial error because I’ve encountered a new error which seemly appeared out of the blue…

Multiple unhandled GraphQL errors found in your files. See the list below to fix them:

Cannot query field "originalId" on type "DatoCmsDatoCmsPostNextContentStructuredTextBlocks".
Cannot query field "image" on type "DatoCmsDatoCmsPostNextContentStructuredTextBlocks".

These types of errors indicate to me that my GraphQL query is trying to retrieve something that doesn’t exist. However, notice how the type name of both errors repeat DatoCms? I haven’t seen this until now, but for reference, here’s the GraphQL query.

export const pageQuery = graphql`
  query ($slug: String!) {
    site: datoCmsSite {
      favicon: faviconMetaTags {
        ...GatsbyDatoCmsFaviconMetaTags
      }
    }
    post: datoCmsPostNext(slug: { eq: $slug }) {
      coverImage {
        alt
        gatsbyImageData(width: 1500)
      }
      title
      summary
      date(formatString: "MMMM DD, YYYY")
      content {
        value
        blocks {
          __typename
          id: originalId
          image {
            alt
            gatsbyImageData(width: 1500)
          }
        }
      }
      slug
      seo: seoMetaTags {
        ...GatsbyDatoCmsSeoMetaTags
      }
    }
  }
`

The weird thing is, I haven’t touched the originalId or image fields in this query since I wrote my initial support ticket, so I’m a little stumped what I did wrong here.

Hey @jessebox , that’s strange, can you email us the project URL where you are making those requests within gatsby so we can take a look at it on our end? You can email us the URL at support@datocms.com

Emailed you this afternoon :slight_smile: