본문 바로가기

리액트

Link태그 a태그 상태 남기 안남기

1. 동작 흐름 한눈에 보기

구분클릭 순간 브라우저가 하는 일React 트리가 어떻게 되나Zustand 스토어는?
Link (Next.js) history.pushState()만 호출 → 네트워크 요청 없음 기존 React 트리 그대로 유지. router.pathname만 바뀌고 필요한 컴포넌트만 리렌더 메모리 그대로. 테마·로그인 등 전역 상태 유지
순수 <a> 새 HTML 요청 → <html> 전체 다시 파싱 기존 React 앱 언마운트 → 새 HTML에 의해 다시 마운트 브라우저 메모리 클리어 → 새로운 store 인스턴스 생성 (초기값으로 리셋)
 

2. 왜 이런 차이가 생길까? - 3단 구조로 뜯어보기

2-1. 브라우저 레이어 – “어디까지 다시 그릴까?”

  • Link
    • 내부적으로 window.history.pushState()(혹은 replaceState) 호출.
    • URL만 바꾼 뒤 fetch()도, <script src> 재실행도 없다.
    • 브라우저는 **“같은 문서 내 뷰 전환”**으로 취급 → DOM·JS Context 그대로.
  • <a>
    • 기본 동작은 HTTP GET & 새 문서 수신.
    • 받은 HTML 헤더부의 <script> 태그를 다시 평가 → React·Zustand 코드를 **“새 인스턴스”**로 로딩.
    • 즉, 기존 Memory Context 자체가 소멸.

2-2. React 레이어 – “컴포넌트를 살릴까 죽일까?”

  • Link 라우팅은 App 컴포넌트 루트 유지.
    • Next.js가 pages/**에 해당하는 컴포넌트만 교체 렌더.
    • React DOM root는 “온전히 살아있다” → Context Provider(Store)도 살아남음.
  • <a> 이동은 React root부터 해체.
    • 새 HTML이 오면 document가 완전히 바뀌므로,
    • 예전 React tree & 모든 state provider 언마운트 → 메모리에서 GC.

2-3. Zustand 레이어 – “Store 인스턴스 수명주기”

상황인스턴스 생성 시점파괴 시점
Single-Page Routing(=Link) 브라우저 탭에서 최초 import 때 한 번 브라우저 탭 닫힐 때
Full Reload(=<a>) 새 페이지에 스크립트가 로드될 때마다 다음 Reload 직전
 

👉 즉, 같은 탭이라도 <a>를 클릭하면 “새 탭 열었다 닫은 것”과 거의 같은 효과


3. 간단 비유 🌊

  • Link : 수영장 안에서 레인만 바꾼다. 물도 그대로고 사람도 그대로.
  • <a> : 아예 다른 수영장으로 이동. 기존 풀장은 불 끄고 문 잠그는 수준이라, 물놀이용 튜브(스토어)도 새로 사야 함.

4. 상태가 필요한 SPA에서 지켜야 할 2가지 수칙

  1. 내부 이동 = 반드시 Link(or router.push) 사용
    • 로고, GNB, 사이드바 전부.
  2. 불가피하게 <a>를 써야 할 땐
    • 외부 도메인이거나, "download" 속성이 필요한 파일 링크 정도로만 한정.

“그럼 새로고침 하면?”

  • 메모리 스토어는 당연히 사라진다. zustand/persist나 localStorage 직접 저장으로 해결 가능(단, 개인정보 암호화 주의).