使用async await在RICHTEXT_OPTIONS内提取Contentful资产

huangapple go评论62阅读模式
英文:

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) =&gt; {
return &lt;p&gt;{children}&lt;/p&gt;;
},
[INLINES.HYPERLINK]: (node: Block | Inline, children: ReactNode) =&gt; {
return &lt;a href={node?.data.uri}&gt;{children}&lt;/a&gt;;
},
// issue with the promise below
[BLOCKS.EMBEDDED_ASSET]: (node: Block | Inline) =&gt; {
const id = node?.data.target.sys.id;
async function getUrls(id: string) {
const Img = await client
.getAsset(id)
.then((asset) =&gt; {
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 (
&lt;Image
width={400}
height={400}
src={`https://${images.imageURL}`}
alt=&quot;random desc&quot;
/&gt;
);
},
},
};
function ClickedArticle({ article }: { article: PostWithCoverImg }){
const { title, date, author, Img, content } = article;
return (
&lt;div className={styles.clickedArticle__article__content}&gt;
{documentToReactComponents(content as Document, RICHTEXT_OPTIONS)}
&lt;/div&gt;
)
}

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 不包括 metadatafields 字段在其类型中。

"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) =&gt; {
  console.log(node);

  // Logs:
  //{
  //  nodeType: &#39;embedded-asset-block&#39;,
  //  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) =&gt; {
      return (
         &lt;Image
           width={400}
           height={400}
           src={node.data.target.fields.file.url}
           alt=&quot;random desc&quot;
         /&gt;
      );
    },

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) =&gt; {
try {
const res = await client.getAssets({&quot;sys.id&quot;: Id})
return &#39;https:&#39;+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.

huangapple
  • 本文由 发表于 2023年2月13日 23:08:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75437683.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定