Next.js部署Vercel后详情页无数据但投票页正常求助
Next.js部署Vercel后详情页无法读取IndexedDB(Dexie.js)数据
问题现象
本地开发时应用功能完全正常,部署到Vercel后出现如下异常:
- 详情页面无法从IndexedDB获取并展示数据,控制台无任何报错信息
- 接收相同props的投票页面可正常读取并展示IndexedDB数据
核心原因分析
- 路由参数就绪时机差异:Vercel生产环境下,Next.js的路由预渲染机制可能导致详情页在
router.query.id未完全加载时就执行数据查询,此时allItems.find无法匹配到数据,最终currentEvent为undefined。而投票页因存在交互触发的状态更新,会在路由参数就绪后重新渲染,从而能正确获取数据。 - 组件未处理数据未就绪状态:详情页直接使用
currentEvent渲染,未等待数据加载完成或路由参数就绪,导致初始渲染时无数据展示。
解决方案
1. 等待路由参数就绪后再查询数据
修改详情页代码,通过useEffect监听路由参数id和allItems的变化,确保两者都就绪后再查找对应事件数据:
import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import DetailsEventData from "@/components/DetailsEventData"; import { optionIcons } from "@/Icons/optionIcon"; function DetailsPage({ allItems }) { const router = useRouter(); const { id } = router.query; const [currentEvent, setCurrentEvent] = useState(null); useEffect(() => { // 确保id和allItems都存在时再查询 if (id && allItems?.length) { const matchedEvent = allItems.find(item => item.eventId === id); setCurrentEvent(matchedEvent); } }, [id, allItems]); // 数据未就绪时显示加载状态 if (!currentEvent) { return <div>加载中...</div>; } function handelEdit() { router.push(`/editpage/${currentEvent.eventId}`); } return ( <StyledMain> <StyledBackLink href={`/`}> <Image src={optionIcons[3].imageSrc} alt={optionIcons[3].description} width={40} height={50} /> </StyledBackLink> <StyledTitle>Event Details</StyledTitle> <DetailsEventData currentEvent={currentEvent} /> <StyledEditImage onClick={handelEdit} src={optionIcons[5].imageSrc} alt={optionIcons[5].description} width={55} height={55} /> </StyledMain> ); } export default DetailsPage;
2. 优化数据加载的容错处理
在_app.js中添加数据加载状态,确保allItems就绪后再渲染子页面:
import { v4 as uuidv4 } from "uuid"; import { useLiveQuery } from "dexie-react-hooks"; import { db } from "@/components/Dexie"; const { eventDetails } = db; export default function App({ Component, pageProps }) { const allItems = useLiveQuery(() => eventDetails.toArray(), []); // 等待数据库数据加载完成 if (!allItems) { return <div>全局加载中...</div>; } async function handleEntryData(data) { try { await db.eventDetails.add({ eventId: uuidv4(), title: data.title, startTime: data.startTime, endTime: data.endTime, location: data.location, introduce: data.introduce, creator: data.creator, }); } catch (error) { alert(`Error: ${error}`); } } return ( <> <GlobalStyle /> <Head></Head> <main> <Component {...pageProps} allItems={allItems} onHandleEntryData={handleEntryData} /> </main> </> ); }
3. 强化详情页展示组件的容错性
修改DetailsEventData组件,确保在currentEvent未就绪时显示友好提示:
import { voteIcons } from "@/Icons/dataIcons"; export default function DetailsEventData({ currentEvent }) { if (!currentEvent) { return <div>加载事件详情中...</div>; } return ( <StyledDetailsCard> <StyledListItem> {!currentEvent.voteResult ? ( "Are You there?" ) : ( <Image src={voteIcons[currentEvent.voteResult].imageSrc} alt={voteIcons[currentEvent.voteResult].description} width={30} height={30} /> )} </StyledListItem> <StyledListItem>{currentEvent.title}</StyledListItem> <StyledListItem>{currentEvent.startTime}</StyledListItem> <StyledListItem>{currentEvent.endTime}</StyledListItem> <StyledListItem>{currentEvent.location}</StyledListItem> <StyledListItem>{currentEvent.introduce}</StyledListItem> <StyledListItem>{currentEvent.creator}</StyledListItem> </StyledDetailsCard> ); }
4. 验证客户端数据一致性
注意IndexedDB是客户端本地存储,部署到Vercel后,新访问的浏览器环境中IndexedDB是空的,需要通过前端操作(比如创建事件)重新添加数据,不要依赖本地开发时的测试数据。
内容的提问来源于stack exchange,提问作者hossi
相关产品推荐
相关产品推荐

