[React] 리액트가 컴포넌트를 기억하는법 State, key

정호·2023년 5월 28일

React

목록 보기
18/30

[React] 상태의 위치(Position)와 Key의 비밀

리액트에서 상태(State)가 어떻게 보존되고 초기화되는지 이해하는 것은 버그 없는 UI를 만드는 데 필수적이다. 리액트가 컴포넌트를 식별하는 기준은 생각보다 단순하면서도 정교하다.


1. 상태의 보존 법칙

스코프란 변수나 함수의 접근 가능한 유효 범위를 의미하듯, 리액트 상태는 컴포넌트의 타입과 UI 트리상의 위치에 묶여 관리됨

리액트는 컴포넌트가 UI 트리에서 같은 위치에 머물러 있는 한 상태를 유지한다. 만약 위치가 바뀌거나 타입이 달라지면 상태는 파괴된다.

상태 보존의 핵심 규칙:

  • 동일 위치 + 동일 타입: 상태가 유지됨 (리렌더링 시에도 데이터 보존)
  • 동일 위치 + 다른 타입: 상태가 초기화됨 (이전 컴포넌트 파기 후 새 컴포넌트 생성)

리액트는 상태를 저장할 때 "이게 UI 트리의 어디에 위치하는가?"를 가장 중요하게 본다.


2. Key: 컴포넌트의 고유 명찰

Key는 리액트가 리스트 내의 각 요소를 식별하여 위치 변화를 추적하게 돕는 식별자임

리스트에서 항목의 순서가 바뀌거나 새로운 항목이 삽입될 때, 리액트는 Key를 보고 "기존에 있던 요소가 이사 갔네" 혹은 "새로운 요소가 들어왔네"를 판단한다.

❌ 잘못된 예: index를 Key로 사용하는 경우

{history.map((item, index) => (
  <HistoryItem key={index} data={item} />
))}
  1. 항목이 배열 맨 앞에 추가되면 기존 0번 데이터가 1번으로 밀려남

  2. 리액트는 key={0}인 첫 번째 줄을 보고 "아직 그대로네"라고 착각함

  3. 실제 데이터는 바뀌었지만, 이전 0번이 들고 있던 상태(강조 표시 등)가 새 데이터에 남아버림

✅ 올바른 예: 고유 ID를 Key로 사용하는 경우


{history.map((item) => (
  <HistoryItem key={item.id} data={item} />
))}

❖ 고유 ID 사용 시의 이점:

  • 데이터가 배열 내 어디로 이동하든 리액트가 해당 Key를 추적한다.

  • 컴포넌트가 이사를 가도 상태가 데이터를 껌딱지처럼 따라다닌다.

3. 응용: Key를 이용한 강제 상태 초기화

Key는 단순히 리스트에서만 쓰이지 않는다. 특정 컴포넌트를 완전히 새로 그려야 할 때(Reset) 고의로 Key를 바꿀 수 있다.

// App.jsx 예시
// chosenCount가 바뀔 때마다 Counter 컴포넌트를 아예 새로 만든다.
<Counter key={chosenCount} initialCount={chosenCount} />
  1. chosenCount가 변경되면 key 값도 같이 변경됨

  2. 리액트는 Key가 바뀌면 "전혀 다른 컴포넌트가 들어왔다"고 판단함

  3. 기존 컴포넌트를 삭제(Unmount)하고 새 컴포넌트를 생성(Mount)하며 내부 useState를 초기화함

profile
열심히 기록할 예정🙃

0개의 댓글