Fix TOC showing wrong headings across navigation

Problem: Table of Contents displayed headings from previously viewed
articles when navigating between posts via client-side routing.

Root cause: PostToc component's useEffect with empty dependency array
only ran once on mount, so it retained stale heading data when React
reused the component instance during navigation.

Solution: Add contentKey prop flow:
- Blog/page routes pass slug to PostLayout
- PostLayout passes contentKey as key prop to PostToc instances
- React remounts PostToc when key changes, rebuilding TOC correctly

Files changed:
- components/post-layout.tsx: Add contentKey prop and key forwarding
- app/blog/[slug]/page.tsx: Pass slug as contentKey
- app/pages/[slug]/page.tsx: Pass slug as contentKey
This commit is contained in:
2025-11-20 15:57:47 +08:00
parent 3748e2f9e8
commit 2b1060dd45
3 changed files with 5 additions and 5 deletions

View File

@@ -79,7 +79,7 @@ export default async function BlogPostPage({ params }: Props) {
return (
<>
<ReadingProgress />
<PostLayout hasToc={hasToc}>
<PostLayout hasToc={hasToc} contentKey={slug}>
<div className="space-y-8">
{/* Main content area for Pagefind indexing */}
<div data-pagefind-body>

View File

@@ -42,7 +42,7 @@ export default async function StaticPage({ params }: Props) {
return (
<>
<ReadingProgress />
<PostLayout hasToc={hasToc}>
<PostLayout hasToc={hasToc} contentKey={slug}>
<div className="space-y-8">
<SectionDivider>
<ScrollReveal>

View File

@@ -12,7 +12,7 @@ function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export function PostLayout({ children, hasToc = true }: { children: React.ReactNode; hasToc?: boolean }) {
export function PostLayout({ children, hasToc = true, contentKey }: { children: React.ReactNode; hasToc?: boolean; contentKey?: string }) {
const [isTocOpen, setIsTocOpen] = useState(hasToc);
return (
@@ -43,7 +43,7 @@ export function PostLayout({ children, hasToc = true }: { children: React.ReactN
transition={{ duration: 0.3 }}
className="h-full overflow-y-auto pr-2"
>
<PostToc />
<PostToc key={contentKey} />
</motion.div>
)}
</AnimatePresence>
@@ -62,7 +62,7 @@ export function PostLayout({ children, hasToc = true }: { children: React.ReactN
className="fixed bottom-24 right-4 z-40 w-72 rounded-2xl border border-white/20 bg-white/90 p-6 shadow-2xl backdrop-blur-xl dark:border-white/10 dark:bg-slate-900/90 lg:hidden"
>
<div className="max-h-[60vh] overflow-y-auto">
<PostToc onLinkClick={() => setIsTocOpen(false)} />
<PostToc key={contentKey} onLinkClick={() => setIsTocOpen(false)} />
</div>
</motion.div>
)}