Le Thinh Blog
Home
Source
Blog

Next.js — Khôi phục lại vị trí scroll khi back lại trang

📆 Thời gian:

🕐 3 phút đọc

#nextjs
#lập trình
Next.js — Khôi phục lại vị trí scroll khi back lại trang

Giới thiệu

Trong khi làm việc trên dự án tiếp theo đầu tiên của tôi và kiểm tra nó từ góc độ người dùng, tôi thấy nó hơi khó chịu, rằng khi sử dụng nút quay lại của trình duyệt, người dùng luôn được đưa lên đầu trang thay vì vị trí mà họ tiếp tục chuyến trang. Sau khi thực hiện một số nghiên cứu và không tìm thấy một giải pháp thỏa mãn, tôi quyết định tự tạo ra một giải pháp.

Triển khai

Đầu tiên ta tạo một Custom Hook, và nó phải được gọi một lần trong dự án của bạn. (Code này viết bằng Typescript nên đặt tên file là usePreserveScroll.ts, khi import phải có đuôi .ts )

import { useRouter } from "next/router"
import { useEffect, useRef } from "react"
export const usePreserveScroll = () => {
 const router = useRouter()
 const scrollPositions = useRef<{ [url: string]: number }>({})
 const isBack = useRef(false)
 useEffect(() => {
   router.beforePopState(() => {
     isBack.current = true
     return true
   })
   const onRouteChangeStart = () => {
     const url = router.pathname
     scrollPositions.current[url] = window.scrollY
   }
   const onRouteChangeComplete = (url: any) => {
     if (isBack.current && scrollPositions.current[url]) {
       window.scroll({
         top: scrollPositions.current[url],
         behavior: "auto",
       })
     }
     isBack.current = false
   }
   router.events.on("routeChangeStart", onRouteChangeStart)
   router.events.on("routeChangeComplete", onRouteChangeComplete)
   return () => {
     router.events.off("routeChangeStart", onRouteChangeStart)
     router.events.off("routeChangeComplete", onRouteChangeComplete)
   }
 }, [router])
}

Sau đó ta tiến hành import Custom Hook vào _app.tsx / _app.js dự án của bạn. 

import { usePreserveScroll } from "./usePreserveScroll.ts";
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
  usePreserveScroll();
  .....
  }

Giải thích

Setup

const router = useRouter()
const scrollPositions = useRef<{ [url: string]: number }>({})
const isBack = useRef(false)

useRouter() cho phép truy cập vào bộ định tuyến tích hợp sẵn của Next.js

scrollPositions là một object, sẽ nhận các key là URL đã truy cập và value là vị trí scroll tương ứng.

isBack sẽ được đặt thành true, khi một điều hướng thông qua browser-back-button (nút back trình duyệt).

Cả 2 scrollPositions isBack đều sử dụng useRef-hook để đảm bảo vẫn giữ được giá trị sau mỗi lần re-render.

useEffect

useEffect(() => {
  ...
}, [router])

Khi router thay đổi, hàm useEffect sẽ được thực thi

beforePopState

router.beforePopState(() => {
  isBack.current = true
  return true
})

router.beforePopState sẽ được gọi khi có popstate event xảy ra (như sử dụng nút back của trình duyệt), có thể đọc thêm tại đây.

Khi đó, isBack sẽ mang giá trị true, return true, do đó Nextjs sẽ tiếp tục xử lý phần còn lại của popstate.

onRouteChangeStart

const onRouteChangeStart = () => {
  const url = router.pathname
  scrollPositions.current[url] = window.scrollY
}

Khi route bắt đầu thay đổi, thì scrollPositions object sẽ lưu giá trị vị trí scroll và key là url của trang hiện tại, sau đó mới tiến hành chuyển đến route đó.

onRouteChangeComplete

const onRouteChangeComplete = (url: any) => {
 if (isBack.current) {
   window.scroll({
     top: scrollPositions.current[url],
     behavior: "auto",
   })
 }
 isBack.current = false
}

Khi route thay đổi thành công, sẽ tiến hành kiểm tra isBack, nếu isBack true thì sẽ tiến hành quay lại vị trí scroll đã lưu ở object scrollPositions. Ở đây behavior được set là “auto” để đảm bảo việc scroll lại tức thì và hiệu ứng chuyển scroll sẽ không được nhìn thấy.

Kết quả

Kết

Tham chiếu: https://jak-ch-ll.medium.com/next-js-preserve-scroll-history-334cf699802a

0

0

0

0

Contents

MYSELF

Lê Văn Thịnh
Lê Văn Thịnh
Tôi chỉ là một người đam mê lập trình web, chia sẻ những gì mình tích luỹ được, góp phần cộng đồng lập trình người Việt.
Theo dõi tôi

Relationship Blogs

Tags

nextjs, scroll nextjs, preserve scroll history, scroll history nextjs, khôi phục vị trí scroll nextjs, cách khôi phục scroll nextjs