英文:
Fetch contentful asset inside RICHTEXT_OPTIONS with async await
问题
I'm using contentful along with react.
To render the content of an article i use the documentToReactComponent from contentful.
when you pass this function an array of content coming from contentful along with some options, it goes through it and renders the data in you html.
my problem: for some reason I need to get the images of the post using client.getAsset(id). Because contentful sends the ids of each images instead of sending the url... this gives me an error because i can resolve the promise returning the data.
here is the code(simpler version):
const RICHTEXT_OPTIONS = {
renderNode: {
[BLOCKS.PARAGRAPH]: (node: Block | Inline, children: ReactNode) => {
return <p>{children}</p>;
},
[INLINES.HYPERLINK]: (node: Block | Inline, children: ReactNode) => {
return <a href={node?.data.uri}>{children}</a>;
},
// issue with the promise below
[BLOCKS.EMBEDDED_ASSET]: (node: Block | Inline) => {
const id = node?.data.target.sys.id;
async function getUrls(id: string) {
const Img = await client
.getAsset(id)
.then((asset) => {
const imageURL = asset.fields.file.url;
const imageTitle = asset.fields.title || asset.fields.file.fileName;
return { imageURL, imageTitle };
})
.catch(console.error);
return Img;
}
const images = getUrls(id);
return (
<Image
width={400}
height={400}
src={`https://${images.imageURL}`}
alt="random desc"
/>
);
},
},
};
function ClickedArticle({ article }: { article: PostWithCoverImg }){
const { title, date, author, Img, content } = article;
return (
<div className={styles.clickedArticle__article__content}>
{documentToReactComponents(content as Document, RICHTEXT_OPTIONS)}
</div>
)
}
When i try to async await the EMBEDDED_ASSET block, it return an error: Objects are not valid as a React child. Because the promise is not resolved correctly.
How can i solve this?(i am using functional components).
英文:
I'm using contentful along with react.
To render the content of an article i use the documentToReactComponent from contentful.
when you pass this function an array of content coming from contentful along with some options, it goes through it and renders the data in you html.
my problem: for some reason I need to get the images of the post using client.getAsset(id). Because contentful sends the ids of each images instead of sending the url... this gives me an error because i can resolve the promise returning the data.
here is the code(simpler version):
const RICHTEXT_OPTIONS = {
renderNode: {
[BLOCKS.PARAGRAPH]: (node: Block | Inline, children: ReactNode) => {
return <p>{children}</p>;
},
[INLINES.HYPERLINK]: (node: Block | Inline, children: ReactNode) => {
return <a href={node?.data.uri}>{children}</a>;
},
// issue with the promise below
[BLOCKS.EMBEDDED_ASSET]: (node: Block | Inline) => {
const id = node?.data.target.sys.id;
async function getUrls(id: string) {
const Img = await client
.getAsset(id)
.then((asset) => {
const imageURL = asset.fields.file.url;
const imageTitle = asset.fields.title || asset.fields.file.fileName;
return { imageURL, imageTitle };
})
.catch(console.error);
return Img;
}
const images = getUrls(id);
return (
<Image
width={400}
height={400}
src={`https://${images.imageURL}`}
alt="random desc"
/>
);
},
},
};
function ClickedArticle({ article }: { article: PostWithCoverImg }){
const { title, date, author, Img, content } = article;
return (
<div className={styles.clickedArticle__article__content}>
{documentToReactComponents(content as Document, RICHTEXT_OPTIONS)}
</div>
)
}
When i try to async await the EMBEDDED_ASSET block, it return an error: Objects are not valid as a React child. Because the promise is not resolved correctly.
How can i solve this?(i am using functional components).
答案1
得分: 1
以下是翻译的内容:
"The node object does contain the asset fields."
作为结果,您不必担心渲染器中的 promises。然而,您将在 TypeScript 中遇到问题,因为 @contentful/rich-text-types
不包括 metadata
和 fields
字段在其类型中。
"Your issue with the Promise was that you didn't await the result of getUrls(id)
. Adding await
in the renderer would make it async and I'm not sure it would work."
关于 Promise 的问题是您没有等待 getUrls(id)
的结果。在渲染器中添加 await
会使它成为异步操作,但我不确定它是否会起作用。
英文:
The node object does contain the asset fields.
// …
[BLOCKS.EMBEDDED_ASSET]: (node) => {
console.log(node);
// Logs:
//{
// nodeType: 'embedded-asset-block',
// data: { target: { metadata: [Object], sys: [Object], fields: [Object] } },
// content: []
//}
return;
},
As a result, you don't have to worry about promises in the renderer. However, you'll have a problem with typescript because @contentful/rich-text-types
does not include the metadata
and fields
fields into its types.
[BLOCKS.EMBEDDED_ASSET]: (node) => {
return (
<Image
width={400}
height={400}
src={node.data.target.fields.file.url}
alt="random desc"
/>
);
},
Your issue with the Promise was that you didn't await the result of getUrls(id)
. Adding await
in the renderer would make it async and I'm not sure it would work.
答案2
得分: 1
你好,我有相同的问题,经过阅读不同的来源后,我制作了这个对我有效的函数:
export const getImage = async (Id) => {
try {
const res = await client.getAssets({"sys.id": Id})
return 'https:'+res.items[0].fields.file.url
}catch(err){
console.log(err)
}
}
英文:
Hello I had the same question and after to read differents sources I made this function that works for me:
export const getImage = async (Id) => {
try {
const res = await client.getAssets({"sys.id": Id})
return 'https:'+res.items[0].fields.file.url
}catch(err){
console.log(err)
}
}
答案3
得分: 0
So it turns out, when you are using contentful, if you fetch data using fetch functions, it will return the asset's id instead of the id.
If you want the whole asset you should use the contentful api to fetch your data. (you get it by installing it in you project).
all you have to do is install contentful
then use the functions provided,
such as contenful.createClient() then using this client client.getEntry()
I think this is the best way of using contentful. You only fetch data once, and you don't have to query contentful to attach your assets. which will reduce the number of request drasticly (imagine you have a blog post with 30 images... fetching thoses images urls separatly when you already fetched the article seems odd.
英文:
So it turns out, when you are using contentful, if you fetch data using fetch functions, it will return the asset's id instead of the id.
If you want the whole asset you should use the contentful api to fetch your data. (you get it by installing it in you project).
all you have to do is install contentful
then use the functions provided,
such as contenful.createClient() then using this client client.getEntry()
I think this is the best way of using contentful. You only fetch data once, and you don't have to query contentful to attach your assets. which will reduce the number of request drasticly (imagine you have a blog post with 30 images... fetching thoses images urls separatly when you already fetched the article seems odd.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论