So, I am building a website for a local business where they can add previous jobs(its a renovation type of business) using contentful cms (sort of a blog of previous jobs).
The problem I have is where I need to display content of each job that is defined in contentful as rich text field.
I will show you my Project component(which is a template for creating pages through gatsby create pages api) and here it is:
import React from 'react';
import { graphql } from 'gatsby';
import { documentToReactComponents } from "@contentful/rich-text-react-renderer"
import { BLOCKS } from "@contentful/rich-text-types"
import Layout from '../components/layout';
const Project = ({data}) => {
const RichContent = JSON.parse(data.contentfulProject.projectContent.raw);
const options = {
renderNode: {
[BLOCKS.HEADING_1]: (node, children) => <h1>{children}</h1>,
// [BLOCKS.EMBEDDED_ASSET]: <img src={`https:${data.contentfulProject.projectContent.references.fluid.src}`}/>,
},
renderMark: {},
}
console.log(data)
return (
<Layout>
{documentToReactComponents(RichContent, options)}
</Layout>
)
}
export default Project;
export const query = graphql`
query($id: String!) {
contentfulProject(id: {eq: $id}) {
title
projectContent {
raw
references {
fluid {
src
}
}
}
}
}
`
So actually I managed to successfully render text fields, but when I uncomment [BLOCKS.EMBEDED_ASSET] the page breaks due to lack of data. Images are not displaying.
My guess is that I can't access json field when querying for contentfull data, I get only raw field back.
Please help :D
Managed to solve the problem, here is the code for working component that properly displays images as well:
import React from 'react'
import { graphql } from 'gatsby';
import { renderRichText } from "gatsby-source-contentful/rich-text"
import { BLOCKS } from "@contentful/rich-text-types"
import Layout from '../components/layout'
function ProjectTemplate({ data }) {
const {projectContent} = data.contentfulProject
console.log(projectContent)
const options = {
renderMark: {},
renderNode: {
[BLOCKS.PARAGRAPH]: (node, children) => <p>{children}</p>,
[BLOCKS.EMBEDDED_ASSET]: node => {
return (
<img src={`https:${node.data.target.fixed.src}`}/>
)
},
},
}
return (
<div>
<Layout>
{renderRichText(projectContent, options)}
</Layout>
</div>
)
}
export default ProjectTemplate
export const query = graphql`
query($id: String!) {
contentfulProject(id: {eq: $id}) {
contentful_id
title
slug
projectContent {
raw
references {
... on ContentfulAsset {
contentful_id
__typename
fixed(width: 1600) {
width
height
src
srcSet
}
}
}
}
}
}
`
Use some structure like:
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)
Each type of field has its own renderNode
, which gives you a lot of flexibility on how do you want to render and style your data with your own components.
With BLOCKS.EMBEDDED_ASSET
your code wasn't returning anything, with the snippet above, you can customize the output, returning an empty object if needed to bypass it.