From 1c74348fae8ccf878beaf7433fdb2977b979d942 Mon Sep 17 00:00:00 2001 From: yiekheng Date: Sun, 12 Apr 2026 14:40:13 +0800 Subject: [PATCH] Sync URL and prev/next nav with the chapter being viewed Once continuous scroll crosses a chapter boundary, the URL was stuck at the originally-opened chapter so browser back / reload would jump the user back there. Double-tap left/right also walked off the wrong chapter since prevChapter/nextChapter were frozen at mount time. - replaceState the URL as currentChapterNum changes (no server refetch). - Derive prevChapter/nextChapter dynamically via useMemo on currentChapterNum, dropping the now-redundant server-computed props. Co-Authored-By: Claude Opus 4.6 (1M context) --- app/manga/[slug]/[chapter]/page.tsx | 12 ------------ components/PageReader.tsx | 23 +++++++++++++++++++---- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/app/manga/[slug]/[chapter]/page.tsx b/app/manga/[slug]/[chapter]/page.tsx index ee1ba58..84a9536 100644 --- a/app/manga/[slug]/[chapter]/page.tsx +++ b/app/manga/[slug]/[chapter]/page.tsx @@ -50,16 +50,6 @@ export default async function ChapterReaderPage({ params }: Props) { const currentChapter = manga.chapters.find((c) => c.number === chapterNum); if (!currentChapter) notFound(); - const chapterIndex = manga.chapters.findIndex( - (c) => c.number === chapterNum - ); - const prevChapter = - chapterIndex > 0 ? manga.chapters[chapterIndex - 1].number : null; - const nextChapter = - chapterIndex < manga.chapters.length - 1 - ? manga.chapters[chapterIndex + 1].number - : null; - const allChapters = manga.chapters.map((c) => ({ id: c.id, number: c.number, @@ -72,8 +62,6 @@ export default async function ChapterReaderPage({ params }: Props) { mangaSlug={manga.slug} mangaTitle={manga.title} startChapterNumber={currentChapter.number} - prevChapter={prevChapter} - nextChapter={nextChapter} chapters={allChapters} initialChapterMeta={initialChapterMeta} /> diff --git a/components/PageReader.tsx b/components/PageReader.tsx index b868e78..1247748 100644 --- a/components/PageReader.tsx +++ b/components/PageReader.tsx @@ -29,8 +29,6 @@ type PageReaderProps = { mangaSlug: string; mangaTitle: string; startChapterNumber: number; - prevChapter: number | null; - nextChapter: number | null; chapters: ChapterMeta[]; initialChapterMeta: PageMeta[]; }; @@ -51,8 +49,6 @@ export function PageReader({ mangaSlug, mangaTitle, startChapterNumber, - prevChapter, - nextChapter, chapters, initialChapterMeta, }: PageReaderProps) { @@ -272,6 +268,25 @@ export function PageReader({ }); }, [mangaSlug, currentChapterNum, currentPageNum]); + // Keep URL in sync with the chapter currently in the viewport so browser + // back / reload returns to the latest chapter, not the one first opened. + useEffect(() => { + const url = `/manga/${mangaSlug}/${currentChapterNum}`; + if (window.location.pathname === url) return; + window.history.replaceState(window.history.state, "", url); + }, [mangaSlug, currentChapterNum]); + + const { prevChapter, nextChapter } = useMemo(() => { + const idx = chapters.findIndex((c) => c.number === currentChapterNum); + return { + prevChapter: idx > 0 ? chapters[idx - 1].number : null, + nextChapter: + idx >= 0 && idx < chapters.length - 1 + ? chapters[idx + 1].number + : null, + }; + }, [chapters, currentChapterNum]); + const router = useRouter(); const touchMovedRef = useRef(false); const singleTapTimerRef = useRef | null>(null);