프로젝트

Next.js Parallel Route 적용기(feat. 웹뷰)

개발하길잘햇다 2024. 12. 27. 19:51
반응형

 

 

현재 회사에서 런칭준비중인 신규 프로젝트에서 Next.js를 사용 중인데,

 

qa기간 중에 있었던 일이다.

 

이슈에 대한 요청사항이 들어왔다.

 

"피드에서 상세페이지 갔다가 돌아오면 스크롤이 맨 위로 올라가 있어요.
스크롤위치 유지시켜 주세요."

 

 

라는 요청사항이었다.

 

문제화면은 아래와 같았다.

 

 

 

잘 보일지 모르겠지만

이미지가 있는 포스트를 눌러서 상세페이지로 이동을 하고,

다시 돌아오면

이미지가 있는 포스트는 보이지 않는다.

이미 맨 위로 스크롤이 초기화되었다는 뜻이다.

 

 

당연했다.

 

상세페이지로 라우팅을 하고

다시 돌아오면서 화면을 새로 렌더링을 하니..

 

 

이 문제를 어떻게 해결해야 할지 고민을 좀 해보니 시도해 볼 법한 방법들이 몇 개 있었다.

 

1. url 파라미터에 현재 스크롤 위치를 저장해서 왕복한다.

2. localStorage 혹은 localSession에 상세페이지 이동시 스크롤 높이를 저장해서 사용한다.

 

두 방법 모두 큰 고민 없이 떠올릴 수 있는 방식이다.

 

근데 여기엔 극복할 수 없는 제한사항이 있었는데, 

 


 

현재 포스트 데이터가 무한 스크롤 방식으로 10개 단위씩 끊어서 불러오고 있다.

 

만약 내가 초반 10개 이내의 포스트 안에서 상세페이지 진입을 하고 나면 상세페이지에서 돌아왔을 때 잘 작동한다.(ok)

 

하지만 10개 이후, 예를 들어 23번째 포스트에서 상세페이지로 진입을 하면

 

스크롤 높이는 전달되지만,

10개씩 끊어서 리스트를 호출하는 방식이다 보니 3번째 api 호출이 다 이루어지고 30개 분량의 리스트가 화면에 렌더링이 된 이후에 23번째 리스트의 높이까지 스크롤링이 이루어져야 한다.

 

대충 적은 거지만 딱 봐도 복잡해 보이고 UX측면에서도 상당히 좋지 않아 보인다.

 

만약 유저가 100번째 포스트에서 상세페이지를 갔다가 돌아왔다면?

 

해보진 않았지만 문제가 생길 거 같다.

 


 

그래서 다시 문제에 대해 고민을 했다.

 

지금 문제가 생기는 원인은 결국 상세페이지에서 피드로 돌아왔을 때,

화면이 새로 렌더링이 되면서 포스트 리스트가 초기화되는 것이다.

 

그럼 화면이 새로 렌더링이 되지 않는다면 스크롤은 유지되지 않을까?

 

라는 생각에서 출발하여 알게 된 방식이 Next.js에서 제공하는 Parallel Routes 였다.

 

Parallel Routes는 말 그대로 한 화면에서 여러 개의 페이지를 띄울 수 있는 방식이다.

 

Parallel Routes

 

 

모달처럼 상세페이지를 띄워서 피드 페이지의 리렌더링을 방지하여 스크롤을 유지시키기 위해 폴더구조부터 정리했다.

 

📦(default)
 ┣ 📂@detail
 ┃ ┣ 📂A-page
 ┃ ┃ ┗ 📂[id]
 ┃ ┃ ┃ ┣ 📜client.tsx
 ┃ ┃ ┃ ┣ 📜default.tsx
 ┃ ┃ ┃ ┗ 📜page.tsx
 ┃ ┃ ┃
 ┃ ┣ 📜default.tsx
 ┃ ┣ 📜layout.tsx
 ┃ ┗ 📜page.tsx
 ┃
 ┣ 📂@feed
 ┃ ┣ 📜client.tsx
 ┃ ┣ 📜default.tsx
 ┃ ┣ 📜layout.tsx
 ┃ ┗ 📜page.tsx
 ┃
 ┗ 📜layout.tsx

 

 

(default) 폴더는 next.js에서 쓸 수 있는 라우트 그룹으로 다양한 레이아웃을 써야 하는 프로젝트에서 유용하기 쓰기 좋은 구조이다.

 

현 프로젝트의 디자인상 레이아웃이 너무 다양해서 사용 중인데 이거 없었으면 어땠을까 싶다... 휴

 

아무튼 다른 부분들은 공식문서 보면 쉽게 다 따라 할 수 있는 부분이라 생략하겠다.

 

눈여겨볼 구간은 폴더 구조중에 default.tsx가 있는데

 

이걸 안 넣으면 해당화면에서 새로고침 했을 때 404 페이지가 나온다.

 

// default.tsx

export default function Default() {
  return <></>
}

 

이렇게 넣어도 되니 잊지 말고 넣으시길..

 

그리고 예시 폴더구조 내부 최상단 layout.tsx 파일은 아래처럼 사용하였다.

 

// layout.tsx
import type { Metadata, Viewport } from 'next'
import { DetailPageLayout } from 'components/layout/DetailPageLayout/DetaillPageLayout'


export default function RootLayout({
  feed,
  detail,
}: Readonly<{
  feed: React.ReactNode
  detail: React.ReactNode
}>) {
  return (
    <>
      {feed}
      <DetailPageLayout>{detail}</DetailPageLayout>
    </>
  )
}

 

 

이러쿵저러쿵하며 적용해 보니

 

아래처럼 리렌더링 없이 스크롤이 유지되면서 상세페이지로 왔다 갔다 할 수 있도록 동작하게 되었다.

 

 

적용 후

 

 

 

상세페이지 이동시 우측에서 슬라이드 형식으로 들어오는 애니메이션은 겸사겸사 넣었다. 

 


마치며

피드로 돌아올 때 페이지가 새로 렌더링이 되지 않으니 화면이 확실히 더 빠르다.

 

한 마리 토끼(스크롤유지) 잡으려다 두 마리를 잡게 된 듯싶다(리렌더링 방지 x -> 속도)

 

이렇게 Parallel Routes 를 통해 나름 성공적으로 요구사항 구현을 하게 되었다.

반응형