본문 바로가기

SPA 이해

MPA·SPA 탐색 구조와 CSR·SSR·SSG 렌더링 전략을 분리하고, 문서 진입·클라이언트 이동·라우팅 책임을 비교합니다.

MPA(Multi Page Application)와 SPA(Single Page Application)는 다른 URL로 이동할 때 새 문서를 여는지, 실행 중인 문서 안에서 화면을 바꾸는지를 구분하는 탐색 구조입니다.

반면 CSR(Client-Side Rendering), SSR(Server-Side Rendering), SSG(Static Site Generation)는 첫 화면의 HTML을 어디에서 언제 만드는지를 설명합니다. 두 분류는 같은 축이 아니므로 SPA가 반드시 CSR이고 MPA가 반드시 SSR인 것은 아닙니다.

React는 UI를 렌더링하는 라이브러리입니다. 라우터, 렌더링 전략, 서버 설정, 캐시와 배포 방식은 React 하나만으로 결정되지 않습니다.

탐색 구조와 렌더링 전략은 서로 다른 축입니다

탐색 방식과 HTML 생성 시점은 독립적인 두 축입니다

REACT ROUTING · URL & RESPONSIBILITY

탐색 방식과 HTML 생성 시점은 독립적인 두 축입니다

MPA·SPA는 URL 이동 때 새 문서를 여는지, CSR·SSR·SSG는 초기 HTML을 어디서 언제 만드는지 설명합니다. 한 축의 이름으로 다른 축이나 성능을 단정하지 않습니다.

하나의 조합 · SSR로 진입한 SPA

GET /products/42
→ 서버가 초기 HTML 생성
hydrateRoot → React 앱 시작
내부 Link → 같은 문서에서 탐색

SSR은 첫 HTML 생성 전략이고 SPA는 실행 뒤 내부 탐색 구조입니다. MPA의 개별 문서에서 CSR로 UI를 완성하는 조합도 가능합니다.

탐색 구조와 렌더링 전략을 섞어 읽지 않기 위한 비교
축 · 선택 무엇을 결정하나 함께 쓸 수 있는 조합
MPA

탐색축

URL 이동 때 서버·CDN에 문서를 요청하고 새 문서를 활성화합니다. SSR·SSG가 흔하지만, 각 문서가 CSR로 UI를 완성하는 구성도 가능합니다.
SPA

탐색축

최초·직접 진입은 문서를 요청하고, 실행 뒤 적합한 내부 이동은 현재 문서에서 라우터가 처리합니다. CSR뿐 아니라 SSR·SSG HTML을 hydrate한 뒤 client navigation을 이어 갈 수 있습니다.
CSR

렌더링축

브라우저가 JavaScript 실행 뒤 초기 UI를 만듭니다. SPA 진입 문서 또는 MPA의 개별 문서 안에서 사용할 수 있습니다.
SSR

렌더링축

요청 시점에 서버가 URL의 초기 HTML을 만듭니다. 그대로 문서 탐색을 이어 가거나, hydrate 후 같은 문서 탐색으로 전환할 수 있습니다.
SSG

렌더링축

빌드 시점에 경로의 HTML을 만들어 정적 호스트·CDN에서 제공합니다. 각 정적 문서로 이동하거나, hydrate 후 client navigation을 사용할 수 있습니다.
탐색축 · MPA
URL 이동마다 새 문서를 요청하고 활성화합니다. 물리적인 HTML 파일이나 요청 시점 SSR을 뜻하지는 않습니다.
탐색축 · SPA
최초·직접 진입은 문서 요청입니다. 앱이 실행된 뒤 적합한 내부 이동만 현재 문서에서 history와 client router로 처리합니다.
렌더링축 · CSR
브라우저 JavaScript가 초기 UI를 만듭니다. SPA뿐 아니라 MPA의 개별 문서에도 사용할 수 있습니다.
렌더링축 · SSR
서버가 요청 시점에 초기 HTML을 만듭니다. hydrate 뒤 client navigation을 계속할 수도 있습니다.
렌더링축 · SSG
빌드 때 경로 HTML을 만듭니다. 정적 문서 탐색과 hydrate된 SPA 모두 구성할 수 있습니다.

SEO와 성능은 구조 이름이 아니라 URL·링크·상태 코드·초기 콘텐츠, JavaScript·hydration 비용, route chunk·data 요청과 캐시를 함께 측정해 판단합니다.

MPA: 이동할 때 새 문서를 여는 구조

MPA에서는 일반적인 링크 이동이나 주소 입력이 브라우저의 문서 탐색(document navigation)을 일으킵니다. 브라우저는 목적 URL을 서버나 CDN에 요청하고 응답받은 HTML을 새 문서로 파싱합니다. 이전 문서의 JavaScript 실행 환경은 일반적으로 끝나지만, 브라우저가 문서를 bfcache에 보관해 뒤로·앞으로 이동에서 복원할 수도 있습니다.

여기서 “여러 페이지”는 URL마다 정적인 HTML 파일이 반드시 하나씩 있다는 뜻이 아닙니다. 서버가 요청 때 HTML을 만들 수도 있고(SSR), 빌드 때 만든 파일을 제공할 수도 있으며(SSG), 응답 문서가 브라우저에서 나머지 UI를 그릴 수도 있습니다(CSR).

MPA의 성질도 구현과 배포에 따라 달라집니다.

  • 새 문서 탐색은 브라우저가 제목, 초점, 스크롤과 문서 수명 주기를 기본 동작으로 처리한다는 장점이 있습니다.
  • 공통 CSS·JavaScript·이미지는 HTTP 캐시에서 재사용될 수 있으므로 페이지마다 모든 리소스를 항상 다시 내려받는 것은 아닙니다.
  • 서버 렌더링 비용은 캐시, CDN, 정적 생성 여부에 따라 달라집니다. “MPA이면 서버 부하가 크다”라고 단정할 수 없습니다.
  • 문서 전환 비용은 있지만, 작은 문서와 캐시·프리페치·뒤로-앞으로 캐시(bfcache)를 잘 활용한 사이트가 SPA보다 반드시 느린 것은 아닙니다.

SPA: 실행 중인 문서 안에서 탐색하는 구조

SPA도 최초 진입, 주소창 입력, 새로고침, 외부 링크 이동에서는 URL의 HTML 문서를 요청합니다. 차이는 앱이 실행된 뒤의 클라이언트 내부 탐색에 있습니다.

라우터는 처리 가능한 같은 출처 링크의 기본 문서 이동을 대신하고 History API로 주소 기록을 갱신한 뒤, 현재 URL의 pathname을 라우트 규칙에 맞춥니다. path parameter와 search parameter는 화면의 대상·보기 조건에, hash는 문서 안 위치나 앱이 정한 상태에 사용할 수 있습니다. 이어서 필요한 컴포넌트와 데이터를 준비하고 React가 현재 문서의 UI를 갱신합니다. 뒤로 가기와 앞으로 가기에서도 라우터가 변경된 history 항목을 다시 해석합니다.

이 과정에서 네트워크 요청이 사라지는 것은 아닙니다. 라우트별 코드 분할을 사용하면 아직 받지 않은 JavaScript 청크를 가져올 수 있고, 화면 데이터도 새로 요청할 수 있습니다. 반대로 이미 받은 청크나 데이터는 캐시 정책에 따라 재사용할 수 있습니다.

SPA가 주는 대표적인 이점은 공통 레이아웃과 일부 메모리 상태를 유지하면서 전환할 수 있다는 점입니다. 그러나 초기 JavaScript, hydration, 데이터 waterfall, 지나치게 큰 번들로 인한 비용이 생길 수 있으므로 “SPA이면 항상 더 빠르다”는 보장은 없습니다.

CSR·SSR·SSG와 hydration

렌더링 전략은 탐색 구조와 별도로 선택하며, 프레임워크는 라우트마다 전략을 섞기도 합니다.

  • CSR: 서버가 앱 진입 문서와 리소스를 보내고, 브라우저의 JavaScript가 초기 UI를 만듭니다. 이미 렌더된 React 마크업이 없다면 일반적으로 createRoot로 시작합니다.
  • SSR: 서버가 요청 시점에 URL의 초기 HTML을 만듭니다. 응답을 캐시하거나 스트리밍할 수도 있으므로 “요청마다 항상 같은 비용으로 전체 HTML을 동기 생성한다”는 뜻은 아닙니다.
  • SSG: 빌드 시점에 경로의 HTML을 만들어 정적 호스팅이나 CDN에서 제공합니다. 콘텐츠 갱신 시점과 재생성 정책은 배포 시스템이 정합니다.
  • hydration: SSR·SSG 등으로 미리 생성한 React HTML을 상호작용 가능한 앱으로 이어 붙이는 과정입니다. hydrateRoot에 전달한 첫 클라이언트 결과는 서버가 만든 마크업과 일치해야 합니다. 정적인 문서나 순수 CSR에는 hydration이 반드시 필요한 것은 아닙니다.

검색 엔진 최적화도 MPA·SPA 이름만으로 결정되지 않습니다. URL별 고유 제목·메타데이터와 링크, 실제 콘텐츠가 담긴 초기 HTML, 올바른 HTTP 상태 코드, 크롤러가 필요한 리소스에 접근할 수 있는지까지 함께 확인해야 합니다. CSR 콘텐츠를 처리하는 검색 엔진도 있지만 모든 크롤러가 같은 수준으로 JavaScript를 실행하는 것은 아니므로, 검색 노출과 빠른 초기 콘텐츠가 중요하면 SSR·SSG 같은 사전 렌더링을 검토합니다.

첫 진입·내부 이동·직접 링크의 책임

SPA의 런타임을 이해하려면 “어떤 URL인가?”보다 먼저 “현재 앱이 이미 실행 중인가?”를 물어야 합니다.

직접 진입과 SPA 내부 이동의 책임 흐름 — 상태 추적

직접 /products/42 진입과 실행 중 내부 이동의 문서/host/router/필요 자원/UI 상태가 다르다. host 404와 app view를 구별하며 createRoot/hydrateRoot를 조건에 맞춰 추적한다.

직접 진입은 호스트부터, 내부 이동은 라우터부터 시작합니다

REACT ROUTING · URL & RESPONSIBILITY

직접 진입은 호스트부터, 내부 이동은 라우터부터 시작합니다

같은 URL도 주소창·새로고침에서는 문서 요청이고, 실행 중인 앱의 적합한 내부 링크에서는 현재 문서의 history 이동입니다. 두 성공 경로는 필요한 리소스를 준비하고 React UI를 갱신합니다.

본문 URL · /products/42의 두 시작점

주소창 / 새로고침 → GET /products/42
앱 내부 링크 → history · pathname 매칭
앱이 준비된 뒤 → chunk / CSS / data → UI

직접 요청의 문서·fallback·실제 404는 서버·CDN 책임입니다. 정적 catch-all이 200을 반환했다면 client NotFound 화면만으로 HTTP 404로 바뀌지 않습니다.

직접 진입과 클라이언트 내부 이동 흐름URL 이동이 실행 중인 앱의 내부 탐색인지 판정된다. 내부 이동은 라우터로, 최초 진입과 새로고침은 문서 요청과 호스트 경로 판정으로 간다. 유효한 경로의 초기 HTML은 React 시작으로, 잘못된 경로는 404로 이어지며, 두 성공 경로는 필요한 라우트 리소스를 확인한 뒤 React UI를 갱신한다. URL 이동실행 중인 앱의내부 탐색인가?브라우저 문서 요청GET /products/42클라이언트 라우터history · pathname match유효한 앱 경로를호스트가 처리하는가?초기 HTML + React 시작client-only: createRootpre-render + JS: hydrateRoot정확한 404 응답라우트 리소스 확인chunk · CSS · datacache · prefetch · networkReact UI 갱신title · focus · scroll · status아니요예유효없음
직접 진입과 클라이언트 내부 이동 흐름URL 이동이 실행 중인 앱의 내부 탐색인지 판정된다. 내부 이동은 라우터로, 최초 진입과 새로고침은 문서 요청과 호스트 경로 판정으로 간다. 유효한 경로의 초기 HTML은 React 시작으로, 잘못된 경로는 404로 이어지며, 두 성공 경로는 필요한 라우트 리소스를 확인한 뒤 React UI를 갱신한다.URL 이동실행 중인 앱의내부 탐색인가?브라우저 문서 요청GET /products/42유효한 앱 경로를호스트가 처리?정확한 404 응답초기 HTML + Reactclient-only:createRootpre-render + JS:hydrateRoot클라이언트 라우터history · pathnamematch라우트 리소스 확인chunk · CSS · datacache · prefetchnetworkReact UI 갱신title · focusscroll · status아니요예없음유효
1 · 최초 진입·직접 링크·새로고침
브라우저가 현재 URL을 문서로 요청합니다. 내부 client route보다 서버·CDN의 경로 처리가 먼저입니다.
2 · 호스트 경계
유효한 URL에는 route별 SSR·SSG HTML 또는 SPA 진입 문서를 반환합니다. 존재하지 않는 경로는 실제 404여야 합니다.
3 · React 시작
client-only shell은 createRoot로 렌더링합니다. 미리 렌더된 React HTML을 상호작용 가능하게 만들 때는 동일한 첫 결과로 hydrateRoot를 수행합니다.
4 · 실행 중인 앱의 내부 이동
적합한 링크를 라우터가 받아 history를 갱신하고 pathname을 라우트에 맞춥니다. params·search·hash는 화면 입력으로 쓰며, 필요한 chunk·CSS·data는 cache, prefetch 또는 network에서 옵니다.
5 · 화면과 경계 검증
React가 UI를 갱신한 뒤 title·focus·scroll·pending/error 안내를 확인합니다. 클라이언트 route guard와 별개로 API·서버가 권한을 강제합니다.

같은 문서의 history 이동은 라우터가 화면을 복원하고, 문서 간 뒤로·앞으로 이동은 브라우저 bfcache가 전체 문서를 복원할 수도 있습니다. 어느 경우든 URL 공유와 재진입 결과를 함께 시험합니다.

이 예의 조건

  • 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
  • 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
관계도의 보충 설명
원도표의 전체 관계·조건·설명
구분내용
원도표 정의 내용유효한 URL에는 route별 SSR·SSG HTML 또는 SPA 진입 문서를 반환합니다. 존재하지 않는 경로는 실제 404여야 합니다.
원도표 정의 내용client-only shell은 createRoot로 렌더링합니다. 미리 렌더된 React HTML을 상호작용 가능하게 만들 때는 동일한 첫 결과로 hydrateRoot를 수행합니다.
전체 상태와 변화 근거
장면현재 관찰값설명변화 이유
직접 /products/42host: 문서 요청 판정 / router: 실행 전문서가 없으면 host에 GET /products/42를 요청한다직접 진입과 현재 앱 내부 이동은 출발점이 다르다
HTML과 필요 자원HTML: 전달 전략에 따른 초기 내용 / 자원: chunk·CSS·data허용한 문서 뒤 createRoot 또는 hydrateRoot와 route 자원을 준비한다404라면 이 성공 경로로 가지 않는다
현재 앱 내부 이동document: 유지 / UI: title/focus/scroll/status 정책이미 실행 중이면 router와 history에서 시작해 필요한 자원 뒤 UI를 갱신한다내부 이동도 코드나 data의 network 요청이 없다는 뜻은 아니다

직접 진입과 SPA 내부 이동의 책임 흐름 — 상태 추적

직접 /products/42 진입과 실행 중 내부 이동의 문서/host/router/필요 자원/UI 상태가 다르다. host 404와 app view를 구별하며 createRoot/hydrateRoot를 조건에 맞춰 추적한다.

직접 진입은 호스트부터, 내부 이동은 라우터부터 시작합니다

REACT ROUTING · URL & RESPONSIBILITY

직접 진입은 호스트부터, 내부 이동은 라우터부터 시작합니다

같은 URL도 주소창·새로고침에서는 문서 요청이고, 실행 중인 앱의 적합한 내부 링크에서는 현재 문서의 history 이동입니다. 두 성공 경로는 필요한 리소스를 준비하고 React UI를 갱신합니다.

본문 URL · /products/42의 두 시작점

주소창 / 새로고침 → GET /products/42
앱 내부 링크 → history · pathname 매칭
앱이 준비된 뒤 → chunk / CSS / data → UI

직접 요청의 문서·fallback·실제 404는 서버·CDN 책임입니다. 정적 catch-all이 200을 반환했다면 client NotFound 화면만으로 HTTP 404로 바뀌지 않습니다.

직접 진입과 클라이언트 내부 이동 흐름URL 이동이 실행 중인 앱의 내부 탐색인지 판정된다. 내부 이동은 라우터로, 최초 진입과 새로고침은 문서 요청과 호스트 경로 판정으로 간다. 유효한 경로의 초기 HTML은 React 시작으로, 잘못된 경로는 404로 이어지며, 두 성공 경로는 필요한 라우트 리소스를 확인한 뒤 React UI를 갱신한다. URL 이동실행 중인 앱의내부 탐색인가?브라우저 문서 요청GET /products/42클라이언트 라우터history · pathname match유효한 앱 경로를호스트가 처리하는가?초기 HTML + React 시작client-only: createRootpre-render + JS: hydrateRoot정확한 404 응답라우트 리소스 확인chunk · CSS · datacache · prefetch · networkReact UI 갱신title · focus · scroll · status아니요예유효없음
직접 진입과 클라이언트 내부 이동 흐름URL 이동이 실행 중인 앱의 내부 탐색인지 판정된다. 내부 이동은 라우터로, 최초 진입과 새로고침은 문서 요청과 호스트 경로 판정으로 간다. 유효한 경로의 초기 HTML은 React 시작으로, 잘못된 경로는 404로 이어지며, 두 성공 경로는 필요한 라우트 리소스를 확인한 뒤 React UI를 갱신한다.URL 이동실행 중인 앱의내부 탐색인가?브라우저 문서 요청GET /products/42유효한 앱 경로를호스트가 처리?정확한 404 응답초기 HTML + Reactclient-only:createRootpre-render + JS:hydrateRoot클라이언트 라우터history · pathnamematch라우트 리소스 확인chunk · CSS · datacache · prefetchnetworkReact UI 갱신title · focusscroll · status아니요예없음유효
1 · 최초 진입·직접 링크·새로고침
브라우저가 현재 URL을 문서로 요청합니다. 내부 client route보다 서버·CDN의 경로 처리가 먼저입니다.
2 · 호스트 경계
유효한 URL에는 route별 SSR·SSG HTML 또는 SPA 진입 문서를 반환합니다. 존재하지 않는 경로는 실제 404여야 합니다.
3 · React 시작
client-only shell은 createRoot로 렌더링합니다. 미리 렌더된 React HTML을 상호작용 가능하게 만들 때는 동일한 첫 결과로 hydrateRoot를 수행합니다.
4 · 실행 중인 앱의 내부 이동
적합한 링크를 라우터가 받아 history를 갱신하고 pathname을 라우트에 맞춥니다. params·search·hash는 화면 입력으로 쓰며, 필요한 chunk·CSS·data는 cache, prefetch 또는 network에서 옵니다.
5 · 화면과 경계 검증
React가 UI를 갱신한 뒤 title·focus·scroll·pending/error 안내를 확인합니다. 클라이언트 route guard와 별개로 API·서버가 권한을 강제합니다.

같은 문서의 history 이동은 라우터가 화면을 복원하고, 문서 간 뒤로·앞으로 이동은 브라우저 bfcache가 전체 문서를 복원할 수도 있습니다. 어느 경우든 URL 공유와 재진입 결과를 함께 시험합니다.

이 예의 조건

  • 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
  • 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.

관계도의 보충 설명

원도표의 전체 관계·조건·설명
구분내용
원도표 정의 내용유효한 URL에는 route별 SSR·SSG HTML 또는 SPA 진입 문서를 반환합니다. 존재하지 않는 경로는 실제 404여야 합니다.
원도표 정의 내용client-only shell은 createRoot로 렌더링합니다. 미리 렌더된 React HTML을 상호작용 가능하게 만들 때는 동일한 첫 결과로 hydrateRoot를 수행합니다.
전체 상태와 변화 근거
장면현재 관찰값설명변화 이유
직접 /products/42host: 문서 요청 판정 / router: 실행 전문서가 없으면 host에 GET /products/42를 요청한다직접 진입과 현재 앱 내부 이동은 출발점이 다르다
HTML과 필요 자원HTML: 전달 전략에 따른 초기 내용 / 자원: chunk·CSS·data허용한 문서 뒤 createRoot 또는 hydrateRoot와 route 자원을 준비한다404라면 이 성공 경로로 가지 않는다
현재 앱 내부 이동document: 유지 / UI: title/focus/scroll/status 정책이미 실행 중이면 router와 history에서 시작해 필요한 자원 뒤 UI를 갱신한다내부 이동도 코드나 data의 network 요청이 없다는 뜻은 아니다

직접 링크와 새로고침

사용자가 /products/42를 주소창에 입력하거나 그 주소에서 새로고침하면 브라우저는 서버에 /products/42 문서를 요청합니다. 배포 계층은 다음 중 하나를 수행해야 합니다.

  • SSR·SSG 경로라면 해당 URL의 문서를 반환합니다.
  • 하나의 진입 문서를 쓰는 client-routed SPA라면 유효한 앱 경로를 진입 HTML로 연결합니다. 이 fallback이 없으면 내부 이동은 되지만 직접 링크에서 404가 날 수 있습니다.
  • 정확한 HTTP 상태가 필요한 배포에서는 존재하지 않는 경로에 실제 404를 반환할 정책을 둡니다. client-only 정적 catch-all이 진입 문서를 200으로 보내는 경우도 있으므로 화면의 찾을 수 없음 UI와 응답 상태를 따로 확인합니다. API·정적 자산·잘못된 URL까지 무조건 진입 HTML과 200으로 바꾸면 오류 처리와 검색 색인이 왜곡됩니다.

React, 라우터, 서버가 맡는 범위

  • 브라우저: 문서 탐색, URL과 history, HTTP 캐시와 문서 수명 주기를 담당합니다.
  • 서버·CDN: URL에 맞는 문서·fallback·404, 캐시 헤더, 보안 헤더를 결정합니다.
  • 라우터: 실행 중인 앱에서 URL을 라우트에 맞추고, 링크 탐색·params·search·라우트 데이터·코드 분할을 연결합니다.
  • React: 선택된 컴포넌트 트리를 렌더링하고 상태 변화에 맞춰 DOM을 갱신하며, 미리 렌더된 React HTML에는 hydration으로 연결됩니다.
  • API·서버: 입력 검증과 인증·인가를 매 요청에서 강제합니다. 클라이언트 라우트 가드나 숨긴 버튼은 사용자 경험을 위한 보조 수단일 뿐 보안 경계가 아닙니다.

React 자체는 라우터도, SSR·SSG 배포 시스템도 아닙니다. 작은 기존 문서의 일부에 React를 추가할 수도 있고, MPA의 각 문서에 독립적인 React 루트를 둘 수도 있으며, 프레임워크로 서버 렌더링한 SPA를 만들 수도 있습니다.

성능·보안·접근성 확인표

구조 이름보다 실제 사용자 흐름을 측정하고 검증합니다.

  • 성능: 초기 HTML의 유용한 콘텐츠, JavaScript와 라우트 청크 크기, hydration 비용, 데이터 요청 waterfall, 캐시 적중과 재방문 전환을 각각 확인합니다.
  • 보안: MPA와 SPA 모두 XSS가 생길 수 있습니다. 신뢰하지 않은 HTML 삽입을 피하고 CSP 같은 방어를 적용하며, 비밀 값과 최종 권한 판정은 클라이언트 번들에 맡기지 않습니다.
  • 접근성: 실제 href가 있는 링크와 의미 있는 문서 구조를 유지합니다. 클라이언트 탐색은 새 문서를 열지 않으므로 라우트 변경 뒤 문서 제목, 주 콘텐츠 초점, 로딩·완료 알림과 스크롤 복원을 앱과 라우터가 명시적으로 설계해야 합니다.
  • 오류 처리: 최초 진입과 내부 이동 모두에서 로딩, 네트워크 실패, 권한 부족, 찾을 수 없는 라우트가 올바른 상태와 복구 동작을 보여야 합니다.

다음 절에서는 React Router를 사용해 URL과 컴포넌트를 연결하는 방법을 배웁니다. 이때도 라우터가 React의 렌더링 책임이나 서버의 보안·배포 책임을 대신하지 않는다는 경계를 유지하세요. 한 URL을 두 가지 진입 방식으로 읽기

같은 /products/42?tab=spec#buy라도 이미 열린 앱의 링크를 누르는 경우와 새 탭 주소창에 붙여 넣는 경우의 첫 책임은 다릅니다. 전자는 실행 중인 라우터가 pathname을 읽고 화면을 바꿀 수 있습니다. 후자는 먼저 호스트가 /products/42?tab=spec의 문서 요청에 응답해야 합니다. fragment인 #buy는 그 HTTP 요청에 포함되지 않습니다. 앱 문서를 받은 뒤에야 라우터와 React가 실행됩니다.

진입 조건을 바꾸어 판단하기

클라이언트 전용 앱의 홈은 이미 열리지만 호스트에는 깊은 경로 fallback이 없다고 가정합니다. 다음 세 결과를 구별해 보세요.

  1. 홈의 앱 링크로 /products/42에 이동합니다.
  2. 그 화면에서 브라우저 새로고침을 누릅니다.
  3. 호스트가 /unknown에도 진입 HTML을 200 OK로 보낸 뒤 앱의 찾을 수 없음 화면이 나옵니다.

각 경우에 먼저 고칠 곳이 라우터의 경로 규칙인지, 호스트의 문서 응답인지 적습니다. 세 번째 화면에 404라는 글자를 쓰면 HTTP 응답도 바뀌는지 함께 설명합니다.

문서와 화면의 경계 해설

첫 번째는 앱 내부에서 정상 라우트가 매칭될 수 있습니다. 데이터 요청까지 반드시 성공한다는 뜻은 아니지만 새 문서 fallback을 거치지 않고 화면을 고릅니다. 두 번째는 /products/42의 새 문서 요청이므로 호스트의 fallback 부재로 실패할 수 있습니다. 이미 확인한 클라이언트 route를 다시 추가하기 전에 호스트의 응답을 확인합니다.

세 번째는 앱이 찾을 수 없음 UI를 표시해도 진입 문서의 응답은 여전히 200 OK입니다. 실제 HTTP 404가 필요한 요구에는 경로를 아는 호스트·서버나 사전 생성 정책이 필요합니다. 화면 메시지와 네트워크 상태를 각각 관찰해야 합니다.