Search code examples
javascriptgraphqlgatsbycontentful

contentful rich text not rendering


I'm trying to log out the raw and so far I can't get anything in the console. It just shows up as an empty array. There must be something wrong with my Query as all i can find on the docs is how to render ContentfulAsset but not actual text which i can format with CSS

/* eslint-disable */
import React from 'react';
import { Helmet } from 'react-helmet';
import { graphql } from 'gatsby';
import Layout from '../components/layout';
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';

export const query = graphql`
    query MyQuery($slug: String) {
        contentfulLongPost(Slug: { eq: $slug }) {
            title
            updatedAt(formatString: "MMMM Do, YYYY")
            body {
                raw
                references {
                    ... on ContentfulAsset {
                        contentful_id
                        __typename
                    }
                }
            }
            free
            contentType
        }
    }
`;

const caseStudy = (props) => {
    console.log(props);

    

    return (
        <Layout>
        
        </Layout>
    );
};

export default caseStudy;

What do I put after __typename to get the raw?

query MyQuery($slug: String) { contentfulLongPost(Slug: {eq: $slug}) { title updatedAt(formatString: "MMMM Do, YYYY") body { raw } } }

`;


Solution

  • There are a few things wrong there... caseStudy must be CaseStudy since it's a React component, otherwise, it will be interpreted as an HTML element which obviously will break your code (<caseStudy> doesn't exist... yet).

    Even if ContentfulAsset fragment is wrong, if your query is correct, you should get something inside the raw field (located at props.data.contentfulLongPost.raw) so check it again. If you are just trying to print the rich text, while your query doesn't break, you can print what's inside raw without data in the ContentfulAsset fragment.

    Maybe what it's wrong if the filter that is hold by the $slug variable, so even if the query is correct, you are not able to fetch the data because there's not any data to fetch.

    Once you ensure that your data is being fetched properly (you have data inside props.data) you can customize the output by lifting your data to:

    import { BLOCKS, MARKS } from "@contentful/rich-text-types"
    import { renderRichText } from "gatsby-source-contentful/rich-text"
    ​
    const Bold = ({ children }) => <span className="bold">{children}</span>
    const Text = ({ children }) => <p className="align-center">{children}</p>
    ​
    const options = {
      renderMark: {
        [MARKS.BOLD]: text => <Bold>{text}</Bold>,
      },
      renderNode: {
        [BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>,
        [BLOCKS.EMBEDDED_ASSET]: node => {
          return (
            <>
              <h2>Embedded Asset</h2>
              <pre>
                <code>{JSON.stringify(node, null, 2)}</code>
              </pre>
            </>
          )
        },
      },
    }
    ​
    renderRichText(node.bodyRichText, options)
    

    Source: https://www.contentful.com/developers/docs/tutorials/general/rich-text-and-gatsby/

    A full customizable example can be checked (almost copy/pasted) at: https://github.com/contentful/rich-text/tree/master/packages/rich-text-react-renderer

    The idea is to create a custom object that will parse your fetched data with a custom HTML/React component:

    import { BLOCKS, MARKS } from "@contentful/rich-text-types"
    import { renderRichText } from "gatsby-source-contentful/rich-text"
    
    const Bold = ({ children }) => <span className="bold">{children}</span>
    const Text = ({ children }) => <p className="align-center">{children}</p>
    
    const options = {
      renderMark: {
        [MARKS.BOLD]: text => <Bold>{text}</Bold>,
      },
      renderNode: {
        [BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>,
        [BLOCKS.EMBEDDED_ASSET]: node => {
          return (
            <>
              <h2>Embedded Asset</h2>
              <pre>
                <code>{JSON.stringify(node, null, 2)}</code>
              </pre>
            </>
          )
        },
      },
    }
    
    function BlogPostTemplate({ data }) {
    
      return <div>{data.contentfulBlogPost && renderRichText(data.contentfulBlogPost, options)}</div>
    }
    

    Where BlogPostTemplate stands for your CaseStudy and contentfulBlogPost for your contentfulLongPost.

    Summarizing:

    • Fix your component naming
    • Check what's inside props.data.contentfulLongPost.raw
    • Check that you have any data with the provided slug. You can force the value of the slug in localhost:8000/___graphql to check what data is fetching your query.
    • Customize the output using the options object and the renderRichText helper