react의 key prop / chatGTP 5버전 이미지 출력

 

 

 

 

리액트에서 배열을 렌더링하기 위해서는 map 메서드를 사용하여 아래와 같이 사용하게된다.

function MyComponent() {
  const items = ['사과', '바나나', '딸기'];

  return (
    <ul>
      {items.map((item, index) => (
        <li>{item}</li>
      ))}
    </ul>
  );
}

리스트 안에 자식들은 key 프롭을 가져야 합니다

단지 배열을 렌더링 했을 분인데 크롬 브라우저에서 에러가 발생한다. 

각 자식 리스트에는 유니크한 키 값을 가져야하는 내용인데 이에 대해 key를 설정하는 이유와 key 설정 시 주의할 점을 알아보고자 한다.

 

key가 필요한 이유

 

Key는 각 컴포넌트가 어떤 배열 항목에 해당하는지 React에 알려주어 나중에 일치시킬 수 있도록 합니다. 이는 배열 항목이 정렬 등으로 인해 이동하거나 삽입되거나 삭제될 수 있는 경우 중요해집니다. key를 잘 선택하면 React가 정확히 무슨 일이 일어났는지 추론하고 DOM 트리에 올바르게 업데이트 하는데 도움이 됩니다.

 

위 내용은 리액트 공식문서에서 key에 대한 내용을 알려주고 있다.

각 항목에 key가 있어야 배열을 추가하거나 삭제, 업데이트할 때 정확하게 처리할 수 있다는 내용이라고 요약할 수 있을 것이다.

 

리액트는 이전 렌더 트리와 다음 렌더 트리를 최소 변경으로 맞추기 위해 형제 노드 단위로 비교한다.

이때 각 형제요소를 식별하는 값이 key가 된다.

key가 없거나 적절치 아니하면 리액트는 요소를 잘못 매칭하거나 불필요하게 교체하게 되어 성능 저하나 입력값에 에러가 발생하는 일이 발생할 수 있다.

 

예를 들어 데이터베이스 sql문에서도 delete from table_name where id = value 와 같이 테이블의 튜플이 가지고 있는 고유한 값(id)을 지정해야 그 데이터를 지울 수 있는 내용과 일맥상통하지 않을까 생각이 된다.

 

 

key를 설정할 때 고려해야 되는 점

 

1. 배열의 인덱스를 key값으로 사용하면 안됩니다

(순서에 상관없는 정적리스트라면 인덱스를 사용하더라도 문제가 되진 않는다)

{todos.map((value, index) => (
  <TodoItem key={index} {...value} />
))}

React는 key를 기준으로 이번에 있던 요소와 새로 렌더링된 요소를 매칭한다.

하지만 index는 아이템의 순서를 나타내기 대문에 순서가 변하면 key가 변경되어버린다.

 

그래서 위와 같이 배열의 인덱스로 key값을 넣는 경우 변경, 삭제, 삽입 시 아이템의 식별이 꼬여 배열 조작에 문제가 발생할 수 있다.

예를 들어 0번 인덱스에 새로운 값을 추가할 경우 기존의 0번 인덱스 항목이 1번으로 변경되어 기존의 인덱스 값들이 변경되어 버린다.

이러한 과정에서 기존의 입력 값들이 다른 항목에게 옮겨져 버리거나 불필요한 DOM 변경이 발생할 수 있다.

 

2. 즉석으로 key를 만들면 안된다.

{items.map(item => (
  <li key={Math.random()}>{item.name}</li>
))}

 

예를 들어 key 값에 Math.random()과 같이 넣는 것인데 이는 매번 호출 때마다 새로운 숫자를 만들게 되어 렌더링할 때마다 key가 전부 변경되는 상황이 발생한다.

 

key가 변경되면 새로운 요소로 판단하여 실제 DOM을 업데이트하게 됩니다. 결국 성능에 영향을 끼치게 됩니다.

 

 

3. key는 prop으로 받지 않는다.

function Item({ id }) {
  return <div>{id}</div>;
}

<Item key={123} id={123} />

위에 코드처럼 Item에 key로 123을 작성하였지만 key의 123은 Item 내부에서 props.key로 접근할 수 없다.

react에서 키는 재조정 과정에서 사용하고 실제 props로는 내려주지 않는다. 컴포넌트 데이터가 아닌 내부 알고리즘을 위한 값이다.

 

<Item key={item.id} id={item.id} />

item.id가 필요한 경우 key로 설정하더라도 다른 Props로 내려주어야 한다.

 

 

4. 데이터베이스의 고유한 key, id를 사용하는 것이 안전하다.

{items.map((item) => (
  <li key={item.id}>{item.name}</li>
))}

key의 고유한 값을 가질 수 있으며 안정적이기 때문에 데이터베이스의 고유한 값을 사용하는 것이 안전하다.

이렇게 되면 각 자식에 고유한 키를 가지게 되어 요소를 변경, 생성, 삭제를 진행하더라도 불필요한 DOM 변경은 사라지게 되고 정확한 변경이 이루어지게 된다.

 

 

* 번외

1) 리스트를 렌더할 때 태그가 아닌 fragment로 사용할 수 있다.

import { Fragment } from 'react';

items.map(item => (
  <Fragment key={item.id}>
    <Title>{item.title}</Title>
    <Content>{item.body}</Content>
  </Fragment>
));

 

 

 

 

 

느낀 점

블로그를 작성하기 전 공식문서와 다른 블로그의 글들을 찾아보며 기존에 알고 있었던 key에 대한 이해가 있었다.

예를 들어 배열 렌더링할 때 키가 있어야 정확하게 리스트를 제거하고 추가, 업데이트 과정을 거칠 수 있다는 것이다.

이번에 다시 찾아보면서 각 배열의 자식 사이에서만 유일하면 되고 전역에서는 유일할 필요가 없다는 사실을 새롭게 인식하게 되었다.

사실 각 배열에 key를 넣으면서 당연시하게 사용했지만 개념적으로 다시 확인할 수 있었던 시간이었다.

그리고 재조정(Reconciliation) 과정인 앞, 뒤의 가상돔을 비교해 변경된 부분만 바뀌는 과정에서 키 값이 정확하지 않으면 비효율적 문제가 발생할 수 있다는 점도 새롭게 알게 되었다.

 

 

참고문서

https://ko.react.dev/learn/rendering-lists#why-does-react-need-keys

 

리스트 렌더링 – React

The library for web and native user interfaces

ko.react.dev

https://ko.legacy.reactjs.org/docs/reconciliation.html#recursing-on-children

 

재조정 (Reconciliation) – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

https://ko.legacy.reactjs.org/docs/lists-and-keys.html

 

리스트와 Key – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

https://www.moonkorea.dev/React-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%9E%AC%EC%A1%B0%EC%A0%95%EA%B3%BC-key

 

React가 고유한 key를 권장하는 이유

리액트는 렌더링 간 효율적으로 DOM을 업데이트하고자 재조정 과정을 거치게 되는데요, 재조정에서 key의 역할과 key 값으로 인덱스의 사용을 지야하는 이유에 대해 알아봅니다.

www.moonkorea.dev

 

'학습 > react' 카테고리의 다른 글

[react] 함수형 컴포넌트와 클래스형 컴포넌트  (3) 2025.08.04
[react] Virtual DOM 가상 돔  (2) 2025.07.24
[react] 리액트의 렌더링 정리  (1) 2025.07.23
클론 프로젝트 회고2  (0) 2024.05.18
클론 프로젝트 회고  (1) 2024.02.12

+ Recent posts