Dùng parallel route cho slot modal cộng intercepting route để chặn điều hướng phía client.
app/
layout.tsx // render {children} và {modal}
page.tsx // feed
@modal/
default.tsx // trả null khi slot không khớp
(.)photo/[id]/page.tsx // bản modal
photo/[id]/page.tsx // bản trang đầy đủTiền tố khớp theo cấp: (.) cùng cấp, (..) lên một cấp, (...) từ thư mục app gốc.
Hành vi thu được:
- Bấm <Link href="/photo/1"> trong feed: điều hướng bị chặn, @modal render modal, feed phía dưới giữ nguyên state và vị trí cuộn. URL vẫn đổi thành /photo/1 nên chia sẻ được.
- Dán thẳng URL hoặc F5: không có điều hướng client để chặn, Next render photo/[id]/page.tsx — trang đầy đủ.
- Back đóng modal vì quay lại entry trước trong history.
Điểm hay vấp:
- Thiếu default.tsx trong slot sẽ gây 404 khi hard-refresh ở route không khớp slot.
- Modal phải là client component để router.back() và bắt phím Esc.
- Hai bản (modal và trang đầy đủ) nên dùng chung một component nội dung, chỉ khác lớp vỏ, tránh lệch dữ liệu.
- useSelectedLayoutSegment('modal') giúp layout biết slot đang mở để khoá cuộn nền.