Routing Layout Navigation

3줄 요약

  • URL은 단순 주소가 아니라 화면 상태, 공유 가능성, 새로고침 복원, 뒤로가기 UX를 결정하는 사용자 인터페이스다.
  • path param은 리소스 정체성, query param은 검색, 필터, 정렬, 페이지 같은 화면 상태에 어울린다.
  • protected route, layout, nested route는 UI 구조이고, API 권한 검사는 백엔드가 최종 담당한다.

핵심 정리

  • SPA routing은 브라우저 새로고침 없이 URL에 맞는 컴포넌트를 렌더링한다.
  • URL에 담긴 상태는 공유와 복원이 가능하지만 민감 정보는 넣으면 안 된다.
  • query parameter는 서버 API parameter와 이름, 기본값, 다중 값 표현을 맞추는 것이 좋다.
  • layout route는 공통 nav, sidebar, auth boundary, error boundary를 구성하는 데 유용하다.
  • navigation state는 일시적이며 새로고침에 약하므로 URL이나 서버에 남아야 하는 상태와 구분한다.

백엔드 개발자가 헷갈리는 지점

  • 프론트 route를 막으면 서버 API도 보호된다고 생각하기 쉽다.
    • 판단 기준은 route guard가 UX이고 보안 경계는 API라는 점이다.
    • 서버 권한 검사는 항상 유지한다.
  • 모든 UI 상태를 React state로만 두기 쉽다.
    • 판단 기준은 공유, 새로고침, 뒤로가기에 의미가 있는지다.
    • 검색 조건과 page는 URL에 두는 편이 좋다.
  • path와 query를 임의로 섞기 쉽다.
    • 판단 기준은 리소스 정체성이 path, 목록 조건이 query다.

개인 프로젝트 기준

  • /projects/:projectId는 상세 리소스, /projects?status=active&page=1은 목록 상태로 둔다.
  • 로그인 필요 route는 protected route로 감싸고, API는 별도 권한 검사를 한다.
  • 목록 화면의 search/filter/sort/page는 URL query param으로 둔다.

확인 질문

  • URL query param에 넣기 좋은 상태는 무엇인가?
    • 검색어, 필터, 정렬, 페이지처럼 공유와 복원이 필요한 상태다.
  • protected route는 보안 경계인가?
    • 아니다. 사용자 경험을 위한 UI 경계이고 API 보안은 서버가 담당한다.
  • path param과 query param의 차이는 무엇인가?
    • path param은 리소스 정체성, query param은 조회 조건이나 화면 상태에 적합하다.

01. URL Layout Navigation 상세

이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • URL을 상태로 본다는 것은 무슨 뜻인가?
  • path param과 query param은 어떻게 나누는가?
  • layout과 protected route는 백엔드 권한 모델과 어떻게 연결되는가?

개요

라우팅은 페이지를 나누는 기술이 아니라 사용자가 앱을 탐색하고, 링크를 공유하고, 새로고침하고, 뒤로가기를 눌렀을 때 같은 맥락을 복원하게 만드는 설계다. 백엔드 개발자에게 URL은 API 리소스 설계와 익숙한 개념이므로, 프론트 route도 리소스 정체성과 화면 상태를 구분해 생각하면 이해하기 쉽다. 좋은 URL은 프론트와 백엔드가 같은 문제를 같은 언어로 설명하게 해준다.

원리

SPA는 브라우저 History API를 사용해 문서 전체를 다시 받지 않고 URL과 화면을 동기화한다. path는 화면이 보여줄 주 리소스를 나타내고, query는 목록 조건이나 UI 상태를 표현하는 데 적합하다. URL에 상태를 두면 공유와 복원이 쉬워지지만, 비밀번호, token, 임시 form 값 같은 민감하거나 휘발적인 값은 넣지 않는다.

코드로 보는 핵심 예시

import { useSearchParams } from "react-router-dom";
 
function ProjectListPage() {
  const [searchParams, setSearchParams] = useSearchParams();
 
  const status = searchParams.get("status") ?? "active";
  const rawPage = Number(searchParams.get("page") ?? "1");
  const page = Number.isInteger(rawPage) && rawPage > 0 ? rawPage : 1;
 
  const projectsQuery = useQuery({
    queryKey: ["projects", { status, page }],
    queryFn: () => fetchProjects({ status, page }),
  });
 
  function changeStatus(nextStatus: string) {
    setSearchParams({ status: nextStatus, page: "1" });
  }
 
  return (
    <>
      <StatusTabs value={status} onChange={changeStatus} />
      <ProjectTable projects={projectsQuery.data ?? []} />
    </>
  );
}

protected route는 사용자 경험을 제어한다.

function RequireAuth({ children }: { children: React.ReactNode }) {
  const meQuery = useQuery({ queryKey: ["me"], queryFn: getCurrentUser });
 
  if (meQuery.isLoading) return <PageSpinner />;
  if (!meQuery.data) return <Navigate to="/login" replace />;
 
  return children;
}

백엔드와 맞춰야 할 지점

  • 프론트 query parameter와 API query parameter 이름을 맞춘다.
  • page index가 0 기반인지 1 기반인지 정한다.
  • sort 문법과 다중 filter 표현을 합의한다.
  • 권한별 접근 가능 route와 API 권한 정책을 함께 문서화한다.

개인 프로젝트 기준

  • 목록 조건은 URL query param과 query key에 넣는다.
  • modal이 공유 가능한 상태라면 URL로 표현하고, 단순 confirm modal은 local state로 둔다.
  • route 단위 layout을 만들어 sidebar, header, auth boundary를 반복하지 않는다.

실전 팁

  • URL에는 민감 정보를 넣지 않는다. 로그, history, referrer에 남을 수 있다.
  • search param 값은 string이므로 number 변환과 기본값을 명시한다.
  • 뒤로가기 UX가 이상하면 “이 상태가 URL에 있어야 했는가”를 먼저 묻는다.
  • query param을 바꿀 때는 page reset, scroll reset, query invalidation까지 함께 확인한다.
  • 관련 함정은 [[02. 백엔드 개발자를 위한 프론트엔드 문법 함정과 디버깅#와-를-섞어-쓰면-어떤-버그가-생길까|=====를 섞어 쓰면 어떤 버그가 생길까?]]와 number input 값이 실제로는 string인 문제를 어떻게 다룰까?를 본다.

위험 신호!

  • 검색 조건을 바꾼 뒤 새로고침하면 상태가 사라진다.
  • URL에 token이나 이메일 인증 secret을 오래 남긴다.
  • 프론트 route guard만 믿고 API 권한 검사를 빼먹는다.
  • API의 page=0과 프론트의 page=1이 섞인다.

확인 질문

확인 질문

  • URL에 상태를 둔다는 것은 어떤 장점이 있는가?
    • 공유, 새로고침 복원, 뒤로가기 UX가 좋아진다.
  • query param 값은 기본적으로 어떤 타입인가?
    • string이다.
  • protected route와 서버 권한 검사는 어떤 관계인가?
    • protected route는 UX 제어이고 서버 권한 검사는 보안 경계다.

참고 문서