React从Contentful获取文章映射报错:TypeError: Cannot read property 'id' of undefined
我来帮你搞定这个问题,你遇到的TypeError: Cannot read property 'id' of undefined其实是个很典型的新手小坑,咱们一步步拆解解决:
错误根源:状态被错误包装成二维数组
你在useEffect里更新状态的时候犯了个小失误:
setArticle([res.items]);
Contentful的getEntries()返回的res.items本身就是一个包含所有文章条目的数组了,你再用[]把它包裹起来,就变成了二维数组(结构大概是[[entry1, entry2, entry3]])。
当你调用article.map()的时候,遍历的是外层数组,第一个entry拿到的是整个res.items数组,而不是单个文章对象,自然没有sys.id属性,所以直接触发报错。
修复步骤
1. 修正状态更新逻辑
把状态更新代码改成直接赋值res.items,去掉多余的数组包裹,同时建议加上错误捕获方便排查问题:
useEffect(() => { client.getEntries() .then((res) => { setArticle(res.items); // 直接传入res.items即可 }) .catch(err => console.error('获取Contentful数据失败:', err)) }, [])
2. 正确处理图片地址
Contentful的媒体资产(比如你的featuredImage)不能直接取sys或者直接用entry.fields.featuredImage,需要访问fields.file.url才能拿到真实的图片链接,同时用可选链?.避免图片字段为空时再次报错:
<img src={entry.fields.featuredImage?.fields.file.url} alt={entry.fields.title || '文章封面'} />
3. 正确渲染富文本内容
你直接渲染entry.fields.body.data的话,页面会显示JSON字符串,Contentful提供了官方的富文本渲染工具,咱们用上它:
首先安装依赖:
npm install @contentful/rich-text-react-renderer
然后在组件中导入并使用:
import { documentToReactComponents } from '@contentful/rich-text-react-renderer'; // 渲染时替换成: {documentToReactComponents(entry.fields.body)}
完整修正后的代码
import React, { useState, useEffect} from 'react' import * as contentful from 'contentful'; import { documentToReactComponents } from '@contentful/rich-text-react-renderer'; const BlogComponent = () => { const [article, setArticle] = useState([]); const client = contentful.createClient({ space: 'xxxxxxxx' , accessToken: 'xxxxxxxxxxxxxxxxxxxxxxxx' }); useEffect(() => { client.getEntries() .then((res) => { setArticle(res.items); }) .catch(err => console.error('获取Contentful数据失败:', err)) }, []) const Articles = article.map((entry) => { return( <div className="entry" key={entry.sys.id}> <h1>{entry.fields.title}</h1> <img src={entry.fields.featuredImage?.fields.file.url} alt={entry.fields.title} /> {documentToReactComponents(entry.fields.body)} </div> ) }) return ( <div> {Articles} </div> ) } export default BlogComponent
这样修改之后,应该就能正常渲染你的文章列表了。如果还有其他字段的问题,记得先console.log(entry)看看具体的数据结构,Contentful的返回数据层级比较多,一定要对应好路径~
内容的提问来源于stack exchange,提问作者Mazino

