goongoguma's blog

Why do I need Keys in React Lists?

React List and Keys

목록(List)은 앱에서 중요한 요소입니다. 모든 어플리케이션들은 어떠한 형태의 목록이든 사용할 수 밖에 없습니다. 달력앱에서는 해야할 일의 목록, 인스타그램에서는 사진들의 목록 그리고 쇼핑카트에서 사야할 물건의 목록처럼 다양한 목록들이 있습니다. 사용 사례는 다양합니다. 어플리케이션에서 사용하는 목록들의 성능은 무거울 수 있습니다. 앱에서 정말 많은 동영상이나 사진의 리스트가 있고 스크롤 할수록 천개 혹은 그 이상을 받아온다고 생각해보세요. 이것은 앱의 성능에 큰 피해를 줄 수 있습니다.

성능은 정말 중요한 요소이기 때문에, 목록을 사용할때는 성능에 최적화 되어 설계 되었는지 확인해야 합니다.

리액트에서 목록을 사용할때는 각각에 아이템에 고유의 키 값이 필요하다는것을 알고 계셨나요? 리액트에서의 목록과 키에 대해 배워보고 어떻게 올바르게 사용할 수 있는지 알아봅시다.

Rendering a simple List component

function ListComponent(props) {
  const listItems = myList.map((item) =>
    <li>{item}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
const myList = ["apple", "orange", "strawberry", "blueberry", "avocado"];
ReactDOM.render(
  <ListComponent myList={myList} />,
  document.getElementById('root')
);

위의 코드는 props로 전달된 아이템의 목록을 랜더하는 ListComponent 를 보여줍니다. render() 메소드 안에서 ListComponent 가 호출되고 myList 라는 이름으로 props 를 받습니다. 해당 코드는 아래의 목록들을 생성합니다.

  • apple
  • orange
  • strawberry
  • avocado

하지만 코드를 실행시키게 되면, 리액트에서 경고가 발생하는것을 보실 수 있을겁니다.

Warning: Each child in an array or iterator should have a unique key prop.%s%s See https://fb.me/react-warning-keys for more information.%s”

보시다시피 경고창은 고유의 키(unique key)에 관한것입니다. 키들은 리액트 앱의 성능을 향상을 위해 필수적인것으로서 그 사용법을 알아보도록 하겠습니다.

How do you use Keys in Lists?

키는 리액트가 어떤 아이템이 변화되었는지(추가되거나/제거되거나/재정렬되거나) 알아보도록 도와줍니다. 배열안의 모든 요소들에게 고유의 정체성을 주기위해서, 키는 필수적입니다.

이것을 이해하기 위해, 위에서 보셨던 코드에 키를 포함시켜 리팩토링 해보겠습니다.

function ListComponent(props) {
  const listItems = myList.map((item) =>
    <li key={item.id}>
       {item.value}
     </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
const myList = [{id: 'a', value: 'apple'},
                {id: 'b', value: 'orange'}, 
                {id: 'c', value: 'strawberry'},
                {id: 'd', value: 'blueberry'}, 
                {id: 'e', value: 'avocado'}];
ReactDOM.render(
  <ListComponent myList={myList} />,
  document.getElementById('root')
);

해당 코드에서 각각의 아이템에 키 값을 포함된것을 보실 수 있습니다. 또한 기존의 목록을 값과 id가 한 쌍인 목록으로 업데이트 했습니다. 배열 각각의 아이템들은 이제 고유의 id값을 가지고 있습니다. 그러므로, id가 각각의 아이템에 키 값으로 배정되게 됩니다. 이 방법은 목록의 아이템에 고유의 키 값을 부여하기 위한 최고의 접근법이라 할 수 있습니다.

해당 메소드에서, 키는 고유의 문자열로서 각각의 아이템들을 식별해줍니다.

Can I just use indexes as keys? — Only under some exceptions

인덱스를 키로 사용하는것은 안티패턴이라는 Robin Pokorny의 을 읽어보시기 바랍니다. 그런데 왜 배열을 순회할때 인덱스를 키로 사용하면 안될까요? 비록 많은 개발자들이 인덱스를 키로 사용했으나 이것은 그렇게 이상적인 행동은 아닙니다. 성능에 부정적인 영향을 미칠수도 있으며 불안정한 컴포넌트 동작에 원인이 될 수 있으므로 리액트는 키 값으로 인덱스의 사용을 권장하지 않습니다.

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);

위의 예제를 보시면, todos를 순회하면서 각각의 아이템에 키 값으로 인덱스를 배정했습니다. 이것은 나중에 아래에서 보게될 일부 허용 사례들에 해당됩니다.

인덱스를 키로 사용할때 목록을 재정렬하거나 혹은 아이템을 목록에 추가, 삭제한다면 컴포넌트 상태(state)에 문제를 일으킬 수도 있습니다. 만약 인덱스가 키라면, 항목이 재정렬될때, 키가 변경될수도 있습니다. 그러므로, 컴포넌트의 상태는 뒤섞이게 되고 다른 컴포넌트의 인스턴스에 전에 쓰던 키 값을 사용할 수도 있습니다.

그러므로, 이러한 관행를 피하고, 고유의 id들이 키로 배정될 수 있도록 해야합니다.

하지만 인덱스를 키로써 사용할 수 있는 몇몇의 상황들이 존재합니다.

What are some exceptions where it is safe to use index as key?

  1. 만약 목록이 정적이고 변함이 없는 경우.
  2. 목록이 다시 정렬되지 않는 경우.
  3. 목록이 필터될 필요가 없는 경우 (목록에서 아이템이 추가 / 제거).
  4. 목록의 아이템이 아이디를 갖고있지 않는 경우.

만일 이러한 경우가 모두 충족된다면, 그때는 인덱스를 키로 사용해도 됩니다.

Note: 인덱스를 키로 사용하게 된다면 컴포넌트내에서 예상치 못한 동작이 발생할 수도 있습니다.

Keys need to be Unique, but only among its siblings

비록 목록에서 각각의 아이템은 고유의 키 값을 가지고 있어야 하지만, 이 규칙은 하나의 배열에서만 적용이 된다는 것을 기억하는게 좋습니다. 다시 말하자면, 배열안의 각각의 아이템들은 고유의 키 값을 가지고 있어야 하지만, 전역적으로 고유할 필요는 없다는 것입니다. 관계가 없는 컴포넌트와 목록에서는 같은 키를 여러번 사용해도 문제가 없습니다.

Keys don’t automatically get passed as a prop to the component

아래의 예제에서, 자식 컴포넌트의 키 값인 item.id를 prop(id) 으로 전달해 주고있습니다. 왜냐하면 리액트는 자동적으로 키를 prop 으로 전달해 주지 않기 때문입니다. 만약 어떤 계산에 키를 사용하려면, 아래의 예제처럼 prop으로 키를 내려줘야 합니다.

const content = items.map((item) =>
  <MyComponent
    key={item.id}
    id={item.id}
    title={item.title} />
);

해당 예제에서, MyComponent 컴포넌트는 props.idprops.title 을 읽을 수 있으나 props.key 는 읽지 못합니다.

Conclusion

이 글에서 중요한 부분들을 다시 되짚어 보겠습니다.

  1. 목록들은 성능이 무거우므로 주의해서 사용해야 합니다.
  2. 목록안의 모든 아이템에 고유의 키 값이 있어야 합니다.
  3. 목록이 정적이지 않다면 (추가되거나 / 재정렬되거나 / 제거되거나) 인덱스들을 키로 사용하는것은 좋지 않습니다.
  4. Math.random() 을 사용해서 키를 생성하는것처럼 불안정한 키 값은 절대 사용하지 마세요
  5. 만약 불안정한 키들을 사용한다면 리액트는 성능이 저하되고 예상하지 못하게 동작할 수 있습니다.

만약 이 글이 좋으셨다면, 공유해주시고 제 트위터를 팔로우 해주세요 @AdhithiRavi

이 글은 원래 이곳에 게재되었습니다. https://programmingwithmosh.com/react/why-do-i-need-keys-in-react-lists/

원문: Why do I need Keys in React Lists? by Adhithi Ravichandran