DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 963,673 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
luke9kim8
luke9kim8

Posted on

Using documentToReactComponents with options

There are many tutorials on how to use Next.js with Contentful, but not a lot talk about how to render rich text files(RTF) with images. In this post, I'll talk about how to render RTFs with images by passing in an option to documentToReactComponents.

Problem

Here is a sample blogpost that I want to publish on my personal website.
Screen Shot 2021-05-10 at 10.46.07 PM

Contentful offers documentToReactComponents function to render its rich text file fields. Install rich-text-react-renderer via npm install @contentful/rich-text-react-renderer.

To use documentToReactComponents, first import it in your component. Then, pass in the rich text file field you fetched from Contentful using client.getEntries().

import {documentToReactComponents} from '@contentful/rich-text-react-renderer'

export async function getStaticProps({params}) {
  const client = createClient({
    space: process.env.CONTENTFUL_SPACE_ID,
    accessToken: process.env.CONTENTFUL_ACCESS_KEY
  })
  const res = await client.getEntries({content_type: 'blogpost'})
   return {
     props: {
       blogposts: res.items
     }
   }
}
Enter fullscreen mode Exit fullscreen mode

In my example, I call client.getEntries() in getStaticProps and call documentToReactComponents in the Blog component JSX. blogpost.fields.blogContent is my rich text file field.

const Blog = ({blogposts}) => {
  return (
    <div>
      <h1>Blog</h1>
      {blogposts.map(blogpost => (
        <div>
          <h1>{blogpost.fields.title}</h1>
          <div>{documentToReactComponents(blogpost.fields.blogContent)}</div>
        </div>
      ))}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

This should render some data on your app, but not all of them. In my situation, I don't see any images despite I embedded them in my RTF.
Screen Shot 2021-05-10 at 10.58.02 PM

Solution

To solve this, we need to specify how to render these embedded data. We can do this by passing a second renderOption parameter to documentToReactComponents.

renderOption is just an object with a renderNode key. The value associated with renderNode is an object specifying how to render the content on the RTF.

const renderOption = {
  renderNode: {
    [BLOCKS.EMBEDDED_ASSET]: (node, children) => {
      return (<Image
        src={`https:${node.data.target.fields.file.url}`}
        height={node.data.target.fields.file.details.image.height}
        width={node.data.target.fields.file.details.image.width}
      />)
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The keys of renderNode specify different types of content (like heading 1, paragraphs, or embedded assets), and the values specify the functions that transform the content to the format we want. This transformation function takes in two parameters: node and children. The node refers to the node itself while the children refers to children node of the specified content.

Β 
Β 
Helpful resources where I got all of these from

Top comments (1)

Collapse
 
lost_semicolon profile image
Lost Semicolon πŸ’»πŸ–±

where did you deploy your app? I am using vercel, and unfortunately when the site is built, my code options are not rendering in the same way they are locally

Visualizing Promises and Async/Await 🀯

async await

☝️ Check out this all-time classic DEV post