Next.js Layout 업데이트 문제: useState 대신 usePathname

nnhw·2025년 8월 23일
0

TIL

목록 보기
9/11
post-thumbnail

Next.js에서 layout.tsx 를 사용하여 마이페이지 레이아웃을 사용하다가 문제가 발생했습니다.

🙊 문제!

이름 옆에 있는 수정 버튼을 클릭하면 다음과 같이 layout의 {children} 부분은 변하지만, layout 에서 컨트롤하고있는 사이드바의 active menu 상태는 변하지 않는 문제였습니다.

제가 기대한대로라면, 이렇게 되었어야 합니다.

  • 사이드 메뉴의 active 표시(색상 있는 부분)가 “프로필 수정”으로 변경
  • 페이지 subtitle도 “프로필 수정”으로 변경


layout.tsx 코드

const [activeMenu, setActiveMenu] = useState('');

return(
   <MainLayout
     title={'마이 페이지'}
     subtitle={activeMenu}
       sidebar={<MypageSidebar activeMenu={activeMenu} setActiveMenu={setActiveMenu} />}
      >
    {children}
  </MainLayout>
 )

🙈 원인

사이드 메뉴와 수정 아이콘 모두 useRouter로 페이지 이동을 하지만, 왜 사이드 메뉴 클릭 시에는 잘 동작하는데 수정 아이콘 클릭 시에는 안 될까요?

그 이유는 바로 Next.js의 Layout은 라우트 이동 시에도 재마운트되지 않기 때문입니다.

즉, layout.tsx 안에서 useState로 관리하는 값은 페이지가 바뀌어도 그대로 유지됩니다.

  • 사이드 메뉴 클릭 시에는 setActiveMenu가 직접 실행되므로 값이 업데이트됨.
  • 반면, 수정 아이콘을 통해 라우트만 이동하면 setActiveMenu는 실행되지 않아서 이전 상태가 그대로 유지되는 것.

🙉 해결

activeMenu는 URL(pathname)에서 파생되는 값인데 굳이 상태로 들고 있었던 게 문제였습니다.

useState 대신 usePathname()을 사용해서 activeMenu를 매번 계산하도록 수정하였습니다.

1. getActiveMenuName 함수 생성

중복되는 로직을 하나로 합치기 위해 getActiveMenuName 함수를 생성했습니다. 매개변수로 받은 menu 목록에서 현재 pathname과 같은 것을 찾아서, name을 반환합니다.

function getActiveMenuName(menus: Menu[], pathname: string) {
  return (
    menus.find(
      (m) => pathname === m.path || pathname.startsWith(m.path + '/')
    )?.name ?? ''
  );
}

2. Layout에서 props로 'activeMenu' 보내주기

const layout = ({ children }: { children: React.ReactNode }) => {
  const pathname = usePathname();
  const menus = createMypageMenus();
  const activeMenu = getActiveMenuName({ menus, pathname });
  return (
    <MainLayout
      title={'마이 페이지'}
      subtitle={activeMenu}
      sidebar={<SideCategory menus={menus} activeMenu={activeMenu} />}
      >
      {children}
    </MainLayout>
  );
};

즉, 코드를 activeMenu를 state대신 usePathname()으로 가져오는 방식으로 수정했으며 그 과정에서 useEffect와 useState 사용을 줄일 수 있었습니다.

😳 느낌점

처음엔 개발 초기라 별 고민 없이 Sidemenu 컴포넌트에서 클릭한 메뉴를 activeMenu 상태로 들고 관리했는데,
곰곰이 생각해보니 이 값은 URL에서 바로 파생되는 거라 usePathname으로 처리하는 게 훨씬 자연스러운 방식이긴합니다. 아마 나중에 다른 페이지를 개발하면서 자연스럽게 리팩토링 했을 것 같은 부분입니다.

하지만 만약 처음부터 usePathname을 썼다면
이번처럼 layout.ts가 라우트 이동 시 재렌더링되지 않는다는 사실은 놓쳤을 수도 있겠죠?!!

개발을 하다 보면 “이렇게 하는 게 왜 더 좋은지” 를 설명하는 것보다,
오히려 “이렇게 하면 왜 안 되는지” 를 이야기하는 경우가 훨씬 많은 것 같습니다.
어떤 로직을 구현하는 방법은 수없이 많지만,안 되는 케이스는 늘 명확하니까요.

아무튼 그래서 이번 경험은 여러의미로 좋은 실수였습니다 (?)
(합리화 아님)

📍 정리

  • Layout은 페이지 이동 시 유지되므로, 내부 useState로 관리하는 값은 바뀌지 않는다.
  • URL에 의해 결정되는 값은 상태로 관리하지 않고 usePathname으로 계산하는 편이 더 안정적이다.
  • 사이드바 같은 네비게이션은 pathname을 소스로 삼아 리팩토링하면 훨씬 깔끔해진다.
profile
웹 프론트엔드 취준생 🥔

0개의 댓글