Next.js中从SSR页面路由到CSR页面避免短暂闪显问题
解决SSR页面跳转CSR页面时的短暂闪显问题
针对你遇到的SSR页面跳转同外观CSR页面时的闪显问题,这里有几个不用加载器就能搞定的方案:
核心原因
这种闪显大多是因为CSR页面完成hydration(客户端渲染)前,旧SSR页面的DOM还没完全移除,或者新页面初始渲染的内容和旧页面有差异,导致视觉跳变。
1. 点击跳转时立即隐藏旧页面内容
在触发路由跳转的瞬间,通过状态控制让当前SSR页面的内容快速隐藏,配合过渡动画让过程更平滑,用户根本察觉不到闪显。
示例代码:
import { useRouter } from 'next/router'; import { useState } from 'react'; export default function SSRPage() { const router = useRouter(); const [isNavigating, setIsNavigating] = useState(false); const goToCSRPage = () => { // 点击后立刻标记为跳转中,隐藏当前页面 setIsNavigating(true); router.push('/csr-page').finally(() => { // 路由完成后重置状态,避免意外情况 setIsNavigating(false); }); }; return ( <div style={{ opacity: isNavigating ? 0 : 1, transition: 'opacity 0.2s ease-out', pointerEvents: isNavigating ? 'none' : 'auto' // 防止跳转中误触 }}> {/* 你的SSR页面内容 */} <button onClick={goToCSRPage}>跳转到CSR页面</button> </div> ); }
2. 抽离共享布局/骨架组件
既然两个页面外观相似,把公共的布局、静态骨架抽成独立组件,让CSR页面在加载数据前先渲染和SSR页面完全一致的骨架内容,这样路由切换时视觉上几乎没有变化。
示例:
// 公共布局组件 components/SharedPageFrame.js export default function SharedPageFrame({ children }) { return ( <> <header className="common-header"> {/* 公共头部 */}</header> <main className="common-container">{children}</main> <footer className="common-footer"> {/* 公共底部 */}</footer> </> ); }
SSR页面直接用:
// pages/ssr-page.js import SharedPageFrame from '../components/SharedPageFrame'; export async function getServerSideProps() { // 服务端数据请求逻辑 return { props: { data: ... } }; } export default function SSRPage({ data }) { return ( <SharedPageFrame> {/* SSR页面的内容,和CSR页面的骨架一致 */} <div className="content-block">{data.content}</div> </SharedPageFrame> ); }
CSR页面先渲染骨架,等数据加载完成再替换:
// pages/csr-page.js import { useState, useEffect } from 'react'; import SharedPageFrame from '../components/SharedPageFrame'; export default function CSRPage() { const [data, setData] = useState(null); useEffect(() => { // 客户端数据请求 fetch('/api/get-data') .then(res => res.json()) .then(setData); }, []); return ( <SharedPageFrame> {/* 先渲染和SSR页面完全一样的骨架 */} {data ? ( <div className="content-block">{data.content}</div> ) : ( <div className="content-block"> {/* 和SSR页面相同的静态占位 */}</div> )} </SharedPageFrame> ); }
3. 预加载CSR页面资源
在SSR页面中提前预加载CSR页面的JS文件,让跳转时资源已经就绪,缩短CSR页面的hydration时间,从根源上减少闪显的可能。
示例代码:
import { useEffect } from 'react'; import { useRouter } from 'next/router'; export default function SSRPage() { const router = useRouter(); useEffect(() => { // 页面加载完成后,后台预加载CSR页面的资源 router.prefetch('/csr-page'); }, [router]); return ( <button onClick={() => router.push('/csr-page')}>跳转到CSR页面</button> ); }
4. 临时禁用SSR页面的卸载动画
如果你的SSR页面加了组件卸载动画,可能会和CSR页面的渲染重叠导致闪显,可以在路由开始切换时禁用动画:
import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; export default function SSRPage() { const router = useRouter(); const [isLeaving, setIsLeaving] = useState(false); useEffect(() => { const startRouteChange = () => setIsLeaving(true); router.events.on('routeChangeStart', startRouteChange); return () => router.events.off('routeChangeStart', startRouteChange); }, [router]); return ( <div className={isLeaving ? 'no-transition' : 'page-transition'}> {/* 页面内容 */} </div> ); }
对应的CSS:
.page-transition { transition: all 0.3s ease; } .no-transition { transition: none !important; }
内容的提问来源于stack exchange,提问作者sdVak
相关产品推荐
相关产品推荐

