rich-text
rich-text copied to clipboard
documentToReactComponents doesn't include images embedded in rich text fields
I am using React and Contentful with Gatsby.
I have defined a rich text field in Contentful. When adding content, I embedded an asset (image) inside the field.
I looks like this
When I query the data, I get the image inside the json
response like this
file": {
"en-US": {
"url": "//images.ctfassets.net/ijv74p5w2k9k/4K8hxN40bRHqnq4iD2OLrw/6392cc793c3bc6ec7c/my-image.jpg",
"details": {
"size": 269327,
"image": {
"width": 1747,
"height": 1240
}
},
"fileName": "my-image.jpg",
"contentType": "image/jpeg"
In my project, I fetched the entire json and rendered it like this
import {documentToReactComponents} from "@contentful/rich-text-react-renderer";
<div className={styles.content}>
{documentToReactComponents(article.content.json)}
</div>
The result is that the text is correctly displayed, but the embedded asset is not displayed.
I am not sure if I'm doing something wrong, not doing something at all or if this is just a bug.
Any suggestions?
I'm having the same issue on Next.js
@Erythros try this it worked for me. You apparently need to define how the method handles the BLOCKS.EMBEDDED_ASSET
. Good luck
@talentedunicorn thank you! That worked for me
119 might have your answer
#119 Doesn't solve anything. It just fallback in case where theres no asset fields Which is my case, querying with GraphQL and using NextJS.
Yep, found that as well. I'm was having the same problem and switched back to the SDK
I had the same issue, like @talentedunicorn says here and I fixed by creating a component that request the asset to the Contentful CDN:
My snippet on rendering the content:
const renderOptions = {
renderNode: {
[BLOCKS.EMBEDDED_ASSET]: (node) => {
return <ContentfulAsset node={node} className={classes.logo} />;
},
},
};
return (<>{documentToReactComponents(contentFullResponse.fields.myFieldId, renderOptions)}</>);
My ContentfulAsset component:
import React, { useCallback, useEffect, useState } from "react";
import { getAsset } from "helpers/providers/contentful";
const ContentfulAsset = ({ node, style, className, testid }) => {
const [isLoading, setIsLoading] = useState(true);
const [asset, setAsset] = useState(null);
const Asset = ({ type, url, alt }) => {
const attr = {
src: url,
style,
className,
["data-testid"]: testid,
};
return (
<>
{type === "image" && <img alt={alt} {...attr} />}
{type === "video" && <video {...attr} />}
</>
);
};
const loadContent = useCallback(() => {
(async () => {
try {
const nodeFields =
node.data.target?.fields ??
(await getAsset(node.data.target.sys.id))?.fields;
const newAsset = {
type: nodeFields?.file?.contentType.split("/")[0],
url: nodeFields?.file?.url,
alt: nodeFields?.title,
};
setAsset(newAsset);
setIsLoading(false);
} catch (e) {
console.error("ContentfulAsset - loadContent", e);
}
})();
}, [node.data.target?.fields, node.data.target.sys.id]);
useEffect(() => {
loadContent();
}, [loadContent]);
return (
<>
{isLoading ? null : (
<>{typeof asset === "object" && <Asset {...asset} />}</>
)}
</>
);
};
export default ContentfulAsset;