본문 바로가기
Dev/React

[React] key가 필요한 이유와 주의할 점

by 5kdk 2022. 12. 10.

들어가며

 React에서 map으로 컴포넌트를 반복 렌더 할 경우 콘솔에서 " Warning: Each child in a list should have a unique "key" prop "이라는 주의 문구를 확인할 수 있는데,  여기서 key는 무엇이며 왜 필요한지에 대해 알아본다.

" Warning: Each child in a list should have a unique "key" prop "

 

 


자식에 대한 재귀적 처리

 DOM 노드의 자식들을 재귀적으로 처리할 때, React는 기본적으로 동시에 두 리스트를 순회하고 차이점이 있으면 변경을 생성한다. 

 

💡 exam

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

// 변경
<ul>
  <li>Connecticut</li> // 자식요소 추가
  <li>Duke</li>
  <li>Villanova</li>
</ul>

 

 위와 같은 경우 React는 <li>Duke</li>와 <li>Villanova</li> 종속 트리를 그대로 유지하는 대신 모든 자식을 변경 (다시 렌더링)한다. 

 React가 setState를 할때를 떠올리면, 비동기로 동작하고 연속적으로 호출했을 때 배치 처리를 했는데, 그 이유는 react는 효율적으로 DOM을 효율적으로 업데이트하기 위함이었다.

React 입장에서 컴포넌트를 반복해서 렌더링 하는 일은 매우 비효율적이기 때문.

 

 


Keys

 이러한 문제를 해결하기 위해 존재하는것이 key 속성이다. 자식들이 key를 가지고 있다면, React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 캐치할 수 있고 효율적으로 렌더링 할 수 있다.

간만히 말해 key는 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정하는 것.

 

💡 exam

<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

// 변경
<ul>
  <li key="2014">Connecticut</li> // 자식요소 추가
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

 

요소에 key를 추가하여 트리의 변환 작업이 효율적으로 수행되도록 수정

 

 

Map()에서의 Key 사용

💡 exam

export default function ListItem({
  onClickTitle,
  badges,
}) {
  return (
    <ListItemLayout>
      <div>
        <div role="button" onClick={onClickTitle} className={styles.title}>
          Issue Example
          {badges &&
            badges.map((badgeProps, idx) => (
              <Badge key={idx} {...badgeProps} />
            ))}
        </div>
        <div className={styles.description}># Description</div>
      </div>
    </ListItemLayout>
  )
}

 

  • map 함수 인자로 전달되는 함수 내부에서 key를 컴포넌트 props를 설정하는 것과 같이 작성한다
  • key는 요소의 '고유한 값'이어야 한다, 배열 요소의 고유한 값을 사용하거나 index로 사용한다
  • 단, 항목의 순서가 바뀔 수 있는 경우 순서가 바뀌면 index도 바뀌기 때문에 권장하지 않는다. 성능이 저하되거나 state관련 문제가 발생하기 때문에, 최후의 수단이다.(하단 주의할 점 참고)

 

 


key 사용 시 주의할 점

  • key는 반드시 변하지 않고, 예상 가능하며, 유일해야 한다. 다시 한번 강조!
  • key 형제 노드에서만 고유하면 된다. 즉, 전역에서 고유할 필요는 없고 해당 배열 안에서만 고유하면 된다.
  • 최후의 수단으로 배열의 인덱스를 key로 사용할 수 있다.
    항목들이 재배열되지 않는다면 이 방법도 잘 동작할 것이지만, 만약 재배열되는 경우 컴포넌트의 state와 관련된 문제가 발생할 수 있다.

    (컴포넌트 인스턴스는 key를 기반으로 갱신되고 재사용되는데 인덱스를 key로 사용하면, 항목의 순서가 바뀌었을 때 key 또한 바뀌기 때문. 그 결과로, 컴포넌트의 state가 엉망이 되거나 의도하지 않은 방식으로 바뀔 수도 있다.)

  • 변하는 key(Math.random()으로 생성된 값 등)를 사용하면 많은 컴포넌트 인스턴스와 DOM 노드를 불필요하게 재생성하여 성능이 나빠지거나 자식 컴포넌트의 state가 유실될 수 있다.

 

 


참고자료

 

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

https://ko.reactjs.org/docs/reconciliation.html

 

'Dev > React' 카테고리의 다른 글

[React] useCallback으로 useEffect 심화 활용  (0) 2022.12.15
[React] useEffect hook 쉽게 알아보기  (0) 2022.12.15
[React] State 살펴보기  (0) 2022.12.04

댓글