👋 Next.js Conf 2024: Come build, party, run, and connect with us! See all events

Tips for using block-content-to-react in a Gatsby app with GraphQL data

13 replies
Last updated: Apr 24, 2020
Are there any videos on how to use the block-content-to-react (https://github.com/sanity-io/block-content-to-react/blob/master/README.md ) inside a gatsby app where I’m already getting the data via gatsby graphql api already?
Apr 19, 2020, 4:09 AM
Hey Saia, I don’t know about any good videos but I can give you some tips.Remember that you cannot (you can with some hacks, but I don’t know how) run GROQ queries in Gatsby, you have to use GraphQL; Use graphiql to create your queries

Then install the block content component as instructed in the repo.

Import it with a const

import BlockContent from "@sanity/block-content-to-react"
Then run it with your data fields, you usually want the fields starting with _raw for block content

<BlockContent blocks={blocks} />

If you want to do things like add CSS classes to your block content data you’ll need to use a serializer.

Here is one that I used recently, note that this is a full component. You can also just define the serializer and pass it to block content like this

<BlockContent blocks={blocks} serializers={someSerializer} />

My component that serializes looks like this


import BaseBlockContent from "@sanity/block-content-to-react"
import React from "react"
import { Link } from "gatsby"
const serializers = {
  types: {
    block(props) {
      switch (props.node.style) {
        case "h1":
          return <h1 className="text-center">{props.children}</h1>
        case "h2":
          return <h2 className="text-center">{props.children}</h2>
        case "h3":
          return <h3 className="text-center">{props.children}</h3>
        case "h4":
          return <h4 className="text-center">{props.children}</h4>
        case "blockquote":
          return <blockquote>{props.children}</blockquote>
        default:
          return <p className="inspirationText">{props.children}</p>
      }
    },
  },
  marks: {
    internalLink: ({ mark, children }) => {
      const { slug = {} } = mark
      const href = `/${slug.current}`
      return <Link to={href}>{children}</Link>
    },
    externalLink: ({ mark, children }) => {
      const { blank, href } = mark
      return blank ? (
        <a href={href} target="_blank" rel="noopener noreferrer">
          {children}
        </a>
      ) : (
        <a href={href}>{children}</a>
      )
    },
  },
}
const BlockContent = ({ blocks }) => (
  <BaseBlockContent blocks={blocks} serializers={serializers} />
)
export default BlockContent
I just import it in my files and run it, I don’t have to pass serializers to it as it already has one. But I do have to pass blocks
Apr 19, 2020, 11:42 AM
In the file where I want to render the rich text data, I have my graphql query like so:
export const query = graphql`
  query($slug: String!) {
    sanityProject(slug: { current: { eq: $slug } }) {
      title
      author {
        name
      }
      slug {
        current
      }
      
      _rawDescription
      image {
        asset {
          fluid {
            ...GatsbySanityImageFluid
          }
        }
      }
    }
  }
`
Apr 19, 2020, 11:43 PM
then I have my component, like so:
const PostTemplate = ({ data: { sanityProject: post } }) => {
  // const htmlDescription = post.description.split("\n").join("<br />")
  console.log("post", post)
  return (
    <>
      <Header />
      <Layout>
        <h1>{post.title}</h1>
        <p
          css={css`
            font-size: 0.75rem;
          `}
        >
          Posted by {post.author.name}
        </p>
        <br />
        {post.image && <Img fluid={post.image.asset.fluid} alt={post.title} />}
        <br />
        {/* {post._rawDescription.map(content => (
          <pre>{JSON.stringify(content, null, 2)}</pre>
        ))} */}

        <ReadLink to="/">&larr; back to all posts</ReadLink>
      </Layout>
    </>
  )
}
export default PostTemplate
Apr 19, 2020, 11:44 PM
What’s the recommended way to rendering my data from sanity with the rich text styles here ^ in my Gatsby app?
Apr 19, 2020, 11:46 PM
Why do you do a
{post._rawDescription.map(content => (
          <pre>{JSON.stringify(content, null, 2)}</pre>
the _raw elements are great for block content, import the block content like I showed in my earlier code (const BlockContent…)
then run &lt;BlockContet blocks={post._rawDescription} /&gt;

Note that if you have any custom types you may need a serializer
Apr 20, 2020, 7:04 AM
user C
is spot on ... just for some extra context, below is how i'm running my PortableText via serializers
query:

fragment SingleArticleFragment on SanityArticle {
    title
    slug {
      current
    }
    ...
    excerpt
    _rawBodyCopy(resolveReferences: { maxDepth: 10 })
    ...
    }
  }
Single page template:

{_rawBodyCopy && <PortableText _blocks_={_rawBodyCopy} />}

PortableText.js component:

import React from 'react'
import BlockContent from '@sanity/block-content-to-react'
import serializers from './Serializers'

const PortableText = ({ blocks }) => (
  <BlockContent blocks={blocks} serializers={serializers} />
)

export default PortableText
Serializer.js

import InlineImage from './InlineImage'

const serializers = {
  types: {
    inlineImage: InlineImage,
  }
}

export default serializers 
Apr 20, 2020, 1:50 PM
also, here's another serializers i have in different project .. the rest of the items are basically the same.
This one just has more components in the PortableText that I can insert during authoring.


import Image from './Image'
import VideoBlock from './Video'
import VideoEmbedBlock from './VideoEmbedBlock'
import GalleryBlock from './GalleryBlock'
import MapBlock from './MapBlock'
import InstagramBlock from './InstagramBlock'

const serializers = {
  types: {
    imageFull: Image,
    video: VideoBlock,
    gallery: GalleryBlock,
    googleMyMap: MapBlock,
    instagramPost: InstagramBlock,
    videoEmbed: VideoEmbedBlock
  }
}

export default serializers
hope this helps
Apr 20, 2020, 1:52 PM
anyone have any idea how
serializers.container
works? I need some specific wrapping container but docs don't really make it clear how to do it 😕
Apr 24, 2020, 9:33 AM
const serializers = {
  container: YourReactElementHere,
}
looks like this works, now to find out how to add props to it
Apr 24, 2020, 9:37 AM
const serializers = {
  container: ({ children }) => (
    <Stack direction="vertical" gap={3}>
      {children}
    </Stack>
  ),
}
sorted
👌
Apr 24, 2020, 9:39 AM
user Y
i think it makes sense for this to be in the docs? Want me to add a PR?
Apr 24, 2020, 9:39 AM
sure! You’re thinking the README.md for the library?
Apr 24, 2020, 9:46 AM
Yep pretty much. Maybe it should be in all the READMEs for the other libs as well actually 🤔
Apr 24, 2020, 9:48 AM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?