시작하며...
이번 프로젝트에서 자유게시판(모집게시판)을 구현하게 되었다.
게시물 상세페이지에 "목록으로" 버튼이 있는데
이를 눌렀을 때, 주소의 param 값이 유지되기 위해 router.back()
을 사용하여 구현하였다.
그러나!!!
게시물 상세페이지를 다른 페이지에서 주소창으로 들어오면 router.back()
이 원하는 의도대로 동작하지 않게 된다. 😭
얘 때문에 그냥 "/boards?page=0"
으로 보낼 수도 없어 고민이 많았다.. 🤔
그래서 이전에 접근했던 페이지를 저장해 가면서 이전 페이지를 확인하여 동작하는 방식을 선택하였다.
이전 페이지 저장하기
어디에 저장할까?
이전 페이지 정보를 어디에 저장할 지 많은 고민을 했다.
- 로컬 스토리지
- 세션 스토리지
- Jotai
- 쿠키 등등.....
각 저장소의 장단점을 살펴보면서 가장 적합한 저장소를 선택했는데 바로 세션 스토리지 이다!!
세션 스토리지에 저장하는 이유
일단 Jotai 같은 경우는 새로고침을 하면 데이터가 유지되지 않아,
새로고침을 해도 데이터가 유지되는 저장소를 선택했다.
그리고 탭 별로 저장이 되기 때문에 여러 개의 탭을 열어도 데이터가 겹치지 않게 된다.
그리고 이전 페이지 정보를 오랫동안 저장해야 할 정보가 아니기 때문에 탭이 닫히는 세션 스토리지를 선택했다.
- 새로고침 시 유지
- 탭 별로 저장됨
- 짧은 유지시간 (탭 닫히면 사라짐)
세션 스토리지로 이전 페이지 저장 구현하기
일단 세션 스토리지는 서버에서 접근하지 못하고 클라이언트에서만 접근할 수 있기 때문에,
클라이언트 컴포넌트를 사용해야 한다. (Next.js App Router 사용 중)
1. 현재 경로 가져오기
현재 페이지의 경로와 쿼리 파라미터 값을 가져오기 위해 usePathnmae 과 useSerchParams 를 import 한다.
import { usePathname, useSearchParams } from "next/navigation";
const usePreviousPage = () => {
const pathname = usePathname();
const searchParams = useSearchParams();
}
2. 경로 가져오기
렌더링 된 후 작동하기 위해 useEffect 를 사용한다.
그래서 세션 스토리지를 가져오고,
pathname 과 seachParams 값을 사용해서 currnetUrl 값을 만들고, 세션 스토리지에 담긴 현재 url 을 previousUrl 라는 이름으로 가져온다.
useEffect(() => {
const storage = sessionStorage;
const currentUrl =
pathname + (searchParams.toString() ? `?${searchParams.toString()}` : "");
const previousUrl = storage.getItem("CURRENT_URL");
}, [pathname, searchParams]);
3. 경로 저장하기
만약 previousUrl 있으면, 그 값은 이제 세션 스토리지에 이전 접근한 url 로 저장한다.
그리고 currentUrl 은 세션 스토리지에 현재 접근한 url 로 저장한다.
useEffect(() => {
const storage = sessionStorage;
const currentUrl =
pathname + (searchParams.toString() ? `?${searchParams.toString()}` : "");
const previousUrl = storage.getItem("CURRENT_URL");
if (previousUrl) {
storage.setItem("PREVIOUS_URL", previousUrl);
}
storage.setItem("CURRENT_URL", currentUrl);
}, [pathname, searchParams]);
4. 컴포넌트 만들기
위에 과정은 이전 페이지를 저장하는 hook 이다.
그래서 해당 hook 을 불러오는 컴포넌트를 만들어야 한다.
const PreviousPageComponent = () => {
usePreviousPage();
return null;
};
5. 비동기 로딩 처리
이전 url 을 저장하기 위해 필요한 값들(pathname, searchParams)이 바로 가져와지는 것이 아니다.
그래서 비동기 처리를 하여 필요한 값들이 다 준비되어야 하기 때문에 Suspense 를 사용했다.
const SuspensePreviousPageComponent = () => (
<Suspense fallback={null}>
<PreviousPageComponent />
</Suspense>
);
export default SuspensePreviousPageComponent;
6. 결과
페이지가 전환될 때마다, 현재와 이전 url 값이 잘 저장되는 것을 확인할 수 있다.
7. 활용하기
"목록으로" 버튼을 눌렀을 때, 이전 페이지가 "/boards"
로 시작했다면 그 페이지로 이동하도록 했다.
그러면 seachParam 값이 유지되어 사용자 경험성 측면에서 향상된다.
그리고 일반적이진 않지만 외부에서 링크를 접속하거나 url 을 입력해서 들어왔을 때를 대비하여, 그런 경우에는 게시물 목록 페이지의 첫 번째인 "/boards"
로 이동하도록 했다.
const handleButtonClickBack = () => {
if (previousPage && previousPage.startsWith("/boards")) {
router.push(previousPage);
} else {
router.push("/boards");
}
};
트러블 슈팅
베타 테스트 피드백
이번 프로젝트에서는 베타 테스트를 진행하여 유저들의 테스트를 받았다.
그런데 피드백 중 아래와 같은 내용을 받게 되었다.
문제 해결
피드백 내용처럼 게시물 상세 페이지에서 새로고침을 하는 경우가 있어, 이전 url 과 현재 url 이 같은 경우에는 세션 스토리지에 업데이트되지 않도록 if문을 추가하였다.
if (previousUrl !== currentUrl) {
if (previousUrl) {
storage.setItem("PREVIOUS_URL", previousUrl);
}
storage.setItem("CURRENT_URL", currentUrl);
}
결과
새로고침을 하고 "목록으로" 버튼을 클릭했을 때 알맞은 목록 페이지로 이동하는 것을 확인할 수 있다.
전체코드
Next.js 에서 세션 스토리지를 사용해서 이전 페이지의 URL 을 저장하고 관리하는 로직의 전체코드는 다음과 같다.
"use client";
import { usePathname, useSearchParams } from "next/navigation";
import { Suspense, useEffect } from "react";
const usePreviousPage = () => {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
const storage = sessionStorage;
const currentUrl =
pathname + (searchParams.toString() ? `?${searchParams.toString()}` : "");
const previousUrl = storage.getItem("CURRENT_URL");
if (previousUrl !== currentUrl) {
if (previousUrl) {
storage.setItem("PREVIOUS_URL", previousUrl);
}
storage.setItem("CURRENT_URL", currentUrl);
}
}, [pathname, searchParams]);
};
const PreviousPageComponent = () => {
usePreviousPage();
return null;
};
const SuspensePreviousPageComponent = () => (
<Suspense fallback={null}>
<PreviousPageComponent />
</Suspense>
);
export default SuspensePreviousPageComponent;
마치며...
사실 그동안 로컬 스토리지, 쿠키만 사용했었지 세션 스토리지를 사용해 본 것은 처음이었다.
각 저장소의 특징을 찾아보고 구현할 내용의 성격에 맞게 세션 스토리지를 선택하여 Next.js 에서 잘 동작하도록 구현하였다.
또한 내가 미처 발견하지 못한 오류를 베타 테스트를 통해 오류를 찾아내어 문제를 해결할 수 있어 좋은 경험이었다.
'💜 프로젝트 구현' 카테고리의 다른 글
[Next.js] Lighthouse 웹 사이트 성능 개선 (100으로 만들기) (0) | 2024.09.10 |
---|---|
[Next.js / TanStack query] useInfiniteQuery 사용하여 무한 스크롤 구현 (feat. cursor 방식) (0) | 2024.09.07 |
[Next.js] 무한 캐러셀 컴포넌트 직접 구현하기 (feat. Tailwind CSS) (2) | 2024.09.02 |
[GitHub Action / Chromatic] 스토리북 PR 미리보기 배포 (feat. yarn) (0) | 2024.08.08 |
DropDown 컴파운드 패턴으로 공통 컴포넌트 구현하기 (0) | 2024.07.29 |
FE 개발자가 되고 싶은 짱잼이
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!