Next.js应用部署Vercel后删除操作页面渲染异常求助
问题描述
本地测试时Next.js应用功能正常,但部署到Vercel(搭配Postgres数据库)后,创建项目/技能功能正常,删除操作异常:数据已从数据库删除,但页面未正确更新,还会出现其他项目凭空消失(实际仍在数据库)的情况。
相关代码
skill-view-card.tsx
'use client' import { deleteSkill, createProject, deleteProject } from '@/app/lib/actions'; import { Button } from '@nextui-org/react'; import { TrashIcon } from '@heroicons/react/20/solid'; export default function SkillViewCard({ skills, projects }: { skills: string; projects: string }) { // 操作后这里获取的是旧数据 const skillsParsed = JSON.parse(skills); // 需要重新获取数据 const projectsParsed = JSON.parse(projects); function toTitleCase(str: string) { return str.replace(/\w\S*/g, (text: string) => text.charAt(0).toUpperCase() + text.substring(1).toLowerCase()); } return ( <div className="p-8 border w-full h-full shadow-lg rounded-md bg-white"> <div className="columns-2"> <div className="text-left text-xl font-bold"> {toTitleCase(skillsParsed?.description) || '暂无描述'} </div> <Button onClick={() => { deleteSkill(skillsParsed.id);}}> <TrashIcon className="h-4 w-4 content-right" /> </Button> </div> <div className="columns-1"> <fieldset> {projectsParsed && projectsParsed.length > 0 ? ( projectsParsed .filter((project: { skill_id: string }) => project.skill_id === skillsParsed?.id) .map((project: { title: string, id: number }) => ( <div key={project.id}> <div>{project.title}</div> <Button onClick={() => { deleteProject(project.id);}}> <p>删除</p> </Button> </div> )) ) : ( <p className="text-gray-500">暂无项目</p> )} </fieldset> </div> <div className="columns-2"></div> <input type="text" placeholder="输入项目标题" className="border rounded-md p-2 w-half" onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); const formData = new FormData(); formData.append('title', e.currentTarget.value); formData.append('skill_id', skillsParsed.id); createProject(formData); e.currentTarget.value = ''; } }} /> </div> ); }
@/app/lib/actions.ts
'use server'; import { sql } from '@vercel/postgres'; import { redirect } from 'next/navigation'; export async function createSkill(formData: FormData) { const skillDescription = formData.get('skill') as string | null; await sql` INSERT INTO skills (description) VALUES (${skillDescription || ''}) `; redirect('/test-page?refetch=true'); // 这里需要重新获取技能数据 } export async function deleteSkill(id: number) { await sql` DELETE FROM skills WHERE id = ${id} `; redirect('/test-page?refetch=true'); } export async function createProject(formData: FormData) { const projectTitle = formData.get('title') as string | null; const skillId = formData.get('skill_id') ? parseInt(formData.get('skill_id') as string, 10) : null; await sql` INSERT INTO projects (title, skill_id) VALUES (${projectTitle || ''}, ${skillId || ''}) `; redirect('/test-page?refetch=true'); } export async function deleteProject(id: number) { await sql` DELETE FROM projects WHERE id = ${id} `; redirect('/test-page?refetch=true'); }
问题根源与解决方案
核心问题:Vercel生产环境的静态缓存
本地开发默认禁用缓存,而Vercel为了性能会对Next.js服务器组件做静态优化缓存。即便删除后重定向带refetch=true参数,服务器仍可能返回缓存的旧数据,导致页面显示异常。
解决步骤
- 强制页面动态渲染
在test-page页面组件顶部添加配置,禁用静态缓存,确保每次请求都从数据库拉取最新数据:
export const dynamic = 'force-dynamic'; // 强制页面每次请求都动态执行数据查询
或者设置无缓存有效期:
export const revalidate = 0; // 效果等同于force-dynamic
- 确保父组件数据是最新的
SkillViewCard作为客户端组件,接收的skills和projects由父服务器组件传递。确保父组件的查询逻辑是动态执行的,比如:
// test-page.tsx 示例 import { sql } from '@vercel/postgres'; import SkillViewCard from './skill-view-card'; export default async function TestPage() { // 每次请求都查询最新数据 const { rows: skills } = await sql`SELECT * FROM skills`; const { rows: projects } = await sql`SELECT * FROM projects`; return ( <div className="grid grid-cols-3 gap-4"> {skills.map(skill => ( <SkillViewCard key={skill.id} skills={JSON.stringify(skill)} projects={JSON.stringify(projects)} /> ))} </div> ); } export const dynamic = 'force-dynamic';
- 验证重定向逻辑
删除操作后的重定向本身没问题,但必须配合页面动态渲染配置才能生效,否则缓存会覆盖新数据的查询结果。
额外说明
本地和生产环境的缓存差异是问题的核心,通过强制动态渲染,就能让页面始终展示数据库中的最新状态,解决删除后页面更新异常的问题。
内容的提问来源于stack exchange,提问作者Cal
相关产品推荐
相关产品推荐

