Next.js中getServerSideProps无法传递更新后Props的问题
核心原因
你的组件将initialEmails(来自props)作为useState的初始值,但useState的初始值仅在组件首次挂载时生效。当你通过<Link>导航回/notifications/emails时,Next.js会复用客户端已挂载的组件实例,此时新的props(initialEmails)已经更新,但组件的本地emails state不会自动同步,因此页面仍显示旧数据。
另外,虽然getServerSideProps已经拿到新数据,但组件没有监听props的变化来更新state,导致视图未刷新。
解决方案
方案1:监听props变化同步state
在组件中添加useEffect,监听initialEmails的变化,一旦props更新就同步到本地state:
const Notifications = ({ emails: initialEmails, error }: Props) => { const [emails, setEmails] = useState<Array<RecordEmail>>(initialEmails); // 监听props变化,同步到state useEffect(() => { setEmails(initialEmails); }, [initialEmails]); // 依赖项为initialEmails,当props更新时触发 return ( <div className="mt-4 flex flex-col space-y-2"> <pre className="bg-gray-100 p-2 font-gtpressuratibold text-xs"> <code>{JSON.stringify(emails, undefined, 2)}</code> </pre> <pre className="bg-gray-100 p-2 font-gtpressuratibold text-xs"> <code>{JSON.stringify(initialEmails, undefined, 2)}</code> </pre> </div> ) }
方案2:直接使用props数据(无需本地state)
如果页面不需要对邮箱数据进行本地临时修改(比如编辑、删除),可以直接使用props中的initialEmails,去掉本地state,这样props更新时视图会自动刷新:
const Notifications = ({ emails: initialEmails, error }: Props) => { return ( <div className="mt-4 flex flex-col space-y-2"> <pre className="bg-gray-100 p-2 font-gtpressuratibold text-xs"> <code>{JSON.stringify(initialEmails, undefined, 2)}</code> </pre> </div> ) }
额外注意:缓存控制
你的getServerSideProps中设置了Cache-Control: private, s-maxage=1, stale-while-revalidate=1,这个设置主要影响CDN或服务器端缓存。根据你的描述,getServerSideProps已经拿到新数据,所以这不是核心问题,但如果后续仍有缓存异常,可以尝试暂时去掉stale-while-revalidate测试。
这是Next.js的预取(Prefetch)机制导致的,属于设计行为:
<Link>组件默认开启prefetch={true},当浏览器处于空闲状态时,会自动预取链接指向的页面资源,包括执行目标页面的getServerSideProps。- 如果你的
activate.tsx页面中存在返回/notifications/emails的<Link>,用户导航到activate页面后,Next.js会在后台预取index.tsx页面,从而触发其getServerSideProps。 - 若刷新
activate页面时也触发,可能是页面中存在其他触发index页面请求的逻辑,但最常见的原因还是预取机制。
如果想禁用预取,可以在<Link>组件上添加prefetch={false}:
<Link href="/notifications/emails" prefetch={false}>返回邮箱列表</Link>
内容的提问来源于stack exchange,提问作者mbecker

