Displaying a collection of contentful rich text with Gatsby

Viewed 251

I am building a Gastby project that uses Contentful to fetch data. In the following example I am trying to display a collection of rich texts.

import React from "react"
import { graphql, useStaticQuery } from "gatsby"
import { INLINES, BLOCKS, MARKS } from "@contentful/rich-text-types"
import { renderRichText } from "gatsby-source-contentful/rich-text"

const LogosGQL = () => {
  const data = useStaticQuery(query)
  const firstRichContent = data.allContentfulAboutUs.nodes

  return (
    <div>
      {firstRichContent.map((page, index) => {
        renderRichText(page.content, options)
      })}
    </div>
  )
}
const options = {
  renderMark: {
    [MARKS.BOLD]: text => <b className="font-bold">{text}</b>,
  },
  renderNode: {
    [INLINES.HYPERLINK]: (node, children) => {
      const { uri } = node.data
      return (
        <a href={uri} className="underline">
          {children}
        </a>
      )
    },
    [BLOCKS.HEADING_1]: (node, children) => {
      return <h1>{children}</h1>
    },
  },
}

const query = graphql`
  {
    allContentfulAboutUs {
      nodes {
        content {
          raw
        }
        contentful_id
      }
    }
  }
`

export default LogosGQL

The error I am seeing is the following:

Error in function renderRichText in ./node_modules/gatsby-source-contentful/rich-text.js:14
Cannot read properties of null (reading 'raw')

./node_modules/gatsby-source-contentful/rich-text.js:14
Open in Editor
  12 | // @ts-check
  13 | function renderRichText({
> 14 |   raw,
     |  ^
  15 |   references
  16 | }, options = {}) {
  17 |   const richText = JSON.parse(raw); // If no references are given, there is no need to resolve them

I know there is something wrong when I try to map my nodes array because when I tried rendering just a single entry,

const LogosGQL = () => {
  const data = useStaticQuery(query)
  const firstRichContent = data.allContentfulAboutUs.nodes[0].content

  return <div>{renderRichText(firstRichContent, options)}</div>
}

I was able to see the output properly rendered on my screen. However, I want the rich text from all my elements. Isn't mapping the nodes array the way to go in this case?

1 Answers

Assuming that the following snippet works:

const LogosGQL = () => {
  const data = useStaticQuery(query)
  const firstRichContent = data.allContentfulAboutUs.nodes[0].content

  return <div>{renderRichText(firstRichContent, options)}</div>
}

It seems that some of the raw data of content node is not properly set in some of the nodes, because the approach is exactly the same.

Try using:

 {firstRichContent.map((page, index) => {
    console.log(index);
    renderRichText(page.content, options)
  })}

To see the offending position

In addition, because of the way that useStaticQuery hook hydrates, it's possible that in use-cases, data comes null (or empty), try also using:

 {firstRichContent && firstRichContent.map((page, index) => {
    console.log(index);
    renderRichText(page.content, options)
  })}

If the snippet above works (meaning that breaks your code in the current scenario) means that the data fetching is not the problem and the issue is in one of the content or raw positions.

In that case to bypass this nullability you just need to:

 {firstRichContent.map((page, index) => {
    if(page.content){
       renderRichText(page.content, options)
    }
  })}
Related