Vite+React应用中Contentful API调用出现fields未定义错误
问题:Contentful数据加载时出现"Cannot read property 'fields' of undefined"错误
使用Contentful作为后端,首次运行应用正常,但再次尝试时出现错误:Cannot read property 'fields' of undefined。相关代码如下:
import { useParams } from 'react-router-dom'; import Footer from './Footer'; import Navbar from './Navbar'; import { useEffect, useState } from 'react'; import * as contentful from 'contentful'; export default function Event() { const { id } = useParams(); const [data, setData] = useState([]); useEffect(() => { async function fetchContentModel() { const client = contentful.createClient({ space: import.meta.env.VITE_CONTENTFUL_SPACE, accessToken: import.meta.env.VITE_CONTENTFUL_PRIVATE_API_KEY, }); const contentModel = await client.getEntries({ content_type: 'posts' }); const contentData = contentModel.items; const res = contentData.reverse(); setData(res); } fetchContentModel(); }, []); let specificEvent = data.find((e) => e.sys.id === id); console.log(specificEvent); return ( <div> <p>{id}</p> <Navbar /> <section> <div className='container px-4 mx-auto mt-5 mb-14'> <div className='max-w-3xl'> <a className='inline-block font-heading text-yellow-400 hover:text-yellow-400 mb-2' href='#' > {specificEvent.fields.type} </a> <h3 className='font-heading text-3xl sm:text-4xl mb-8'> {specificEvent.fields.postTitle} </h3> </div> </div> <img className='block w-full h-112 object-cover' src={specificEvent.fields.postCover.fields.file.url} alt='' /> <div className='container px-4 mx-auto'> <div className='max-w-3xl mx-auto pt-12 pb-14'> <p className='text-lg leading-8 mb-6'> {specificEvent.fields.postContent} </p> </div> </div> </section> <Footer /> </div> ); }
原因分析
- 组件初始化时,
data是初始空数组,data.find()返回undefined,此时直接访问specificEvent.fields会触发错误。 useEffect的依赖项为空数组,仅在组件挂载时请求一次数据。当路由参数id变化时,不会重新请求数据,若旧数据中没有新id对应的条目,specificEvent会是undefined。
解决方案
1. 添加加载状态与空值校验
在数据加载完成前显示加载提示,同时对specificEvent进行空值校验,避免访问不存在的属性:
import { useParams } from 'react-router-dom'; import Footer from './Footer'; import Navbar from './Navbar'; import { useEffect, useState } from 'react'; import * as contentful from 'contentful'; export default function Event() { const { id } = useParams(); const [data, setData] = useState([]); const [loading, setLoading] = useState(true); // 添加加载状态 useEffect(() => { async function fetchContentModel() { setLoading(true); // 开始加载时设为true const client = contentful.createClient({ space: import.meta.env.VITE_CONTENTFUL_SPACE, accessToken: import.meta.env.VITE_CONTENTFUL_PRIVATE_API_KEY, }); const contentModel = await client.getEntries({ content_type: 'posts' }); const contentData = contentModel.items; const res = contentData.reverse(); setData(res); setLoading(false); // 加载完成设为false } fetchContentModel(); }, [id]); // 添加id作为依赖,参数变化时重新请求 let specificEvent = data.find((e) => e.sys.id === id); // 加载中显示提示 if (loading) { return <div>加载中...</div>; } // 找不到对应条目时显示提示 if (!specificEvent) { return <div>未找到该活动</div>; } return ( <div> <p>{id}</p> <Navbar /> <section> <div className='container px-4 mx-auto mt-5 mb-14'> <div className='max-w-3xl'> <a className='inline-block font-heading text-yellow-400 hover:text-yellow-400 mb-2' href='#' > {specificEvent.fields.type} </a> <h3 className='font-heading text-3xl sm:text-4xl mb-8'> {specificEvent.fields.postTitle} </h3> </div> </div> <img className='block w-full h-112 object-cover' src={specificEvent.fields.postCover.fields.file.url} alt={specificEvent.fields.postTitle} // 添加有意义的alt文本 /> <div className='container px-4 mx-auto'> <div className='max-w-3xl mx-auto pt-12 pb-14'> <p className='text-lg leading-8 mb-6'> {specificEvent.fields.postContent} </p> </div> </div> </section> <Footer /> </div> ); }
2. 优化:直接请求单个条目(可选)
如果不需要所有posts数据,直接通过id请求单个条目可以减少数据传输,提升性能:
useEffect(() => { async function fetchSingleEvent() { setLoading(true); const client = contentful.createClient({ space: import.meta.env.VITE_CONTENTFUL_SPACE, accessToken: import.meta.env.VITE_CONTENTFUL_PRIVATE_API_KEY, }); try { const entry = await client.getEntry(id); // 直接请求单个条目 setData([entry]); // 保持data数组结构,或改为单个状态 setLoading(false); } catch (error) { console.error('获取条目失败:', error); setLoading(false); } } fetchSingleEvent(); }, [id]);
内容的提问来源于stack exchange,提问作者meddhiaka
相关产品推荐
相关产品推荐

