[TIL] React : List & Key
배열의 렌더링 📘
이전에 학습했던 생명주기 부분에서 render()
의 반환 값에 대한 내용을 다시금 생각하면, 배열(Array
)와 Fragments 가 이에 해당 함을 기억할 것이다. 이에 대한 공식 문서를 찾아보면, key
가 있는 Fragments에 대한 부분에서 map
을 활용한 배열의 렌더링을 확인할 수 있다.
배열은 목록 형태의 컴포넌트를 렌더링 할 때 유용하다. 또한, 배열을 렌더링 함에 있어 map()
메서드를 함께 활용하면 불필요한 반복을 줄일 수 있어 보다 간략한 코드를 만들어 낼 수 있다.
다음의 예시에서 객체 배열을 map()
메서드를 통해 객체 형태의 React Elements를 요소로 갖는 새로운 배열로 반환하였고, 이를 렌더링할 수 있음을 확인하였다. 아래는 렌더링 된 DOM의 트리 구조이다.
또한 예시를 자세히 보면, 각 객체의 id
라는 property
값을 key
값으로 할당한 것을 확인할 수 있다. 그렇다면 왜 굳이 key
를 설정하는 지에 대해 알아볼 필요가 있다. 이를 위해 이어지는 내용에서 key
유무에 따른 업데이트 방식의 차이와, 올바른 key
사용법 등을 함께 알아본다.
Key
🔑
공식 문서에서는 Key
의 역할과 지정 방식을 다음과 같이 정의하고 있다.
어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는다.
또한, 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부 엘리먼트에 지정해야 한다.
이렇게 간단히 한 문장을 통해 정리되었지만, 직관적으로 이해하기 힘드니 각 부분을 풀어서 알아보자.
key
유무에 따른 업데이트 방식의 차이
우선 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는다는 것은 key
유무에 따른 업데이트 방식의 차이를 통해 이해할 수 있다.
const array = ['a', 'b', 'c', 'd'];
array.map(item => <div>{item}</div>);
위 예시처럼 렌더링을 진행한다고 가정하고 새로운 요소인 e
를 해당 배열 중간인 b
와 c
사이에 추가하고자 할 때, 리렌더링 되는 과정은 다음과 같다.
- 배열 내
c
가z
로 변경 - 그 다음 요소인
d
가c
로 변경 - 배열 마지막에
d
를 추가
단순히 b
를 찾고, 그 다음 요소에 c
를 삽입하는 것으로 예상했지만, 상당히 비효율적인 과정을 거치고 있음을 알 수 있다. 추가로, 현재 상태에서 배열 맨 첫 번째 요소인 a
를 제거하고자 할 때에는 다음과 같이 리렌더링 된다.
- 배열 내
a
가b
로 변경되고, 순서대로c
까지d
로 변경 - 마지막 요소인
d
제거
요소의 제거 또한 비효율적인 과정을 거침을 알 수 있다.
이러한 비효율적인 과정을 key
를 통해 해결할 수 있다.
const array = [
{
id: 0,
text: 'a'
},
{
id: 1,
text: 'b'
},
{
id: 2,
text: 'c'
},
{
id: 3,
text: 'd'
}];
array.map(item => (<div key={item.id}>{item.text}</div>));
위 예시를 보면 기존 단순 배열 형태에서 객체 배열 형태로 바뀌고 기존 값을 text
프로퍼티에, 추가적으로 id
프로퍼티에 숫자 값을 입력한 것을 확인할 수 있다. 여기서 id
값을 자세히 보면 각 배열의 index
값에 해당한다고 생각하여 단순히 key
값에 index
값을 할당하는 것이 맞다고 생각할 수 있지만, key
값에 index
값을 할당했을 때, 발생할 수 있는 문제점이 있기에 별도의 id
값을 할당한다.
💡 key
값에 index
를 할당하면 발생하는 오류
위와 같은 예시에서
key
값을 고유한 값이 아닌index
값을 할당하며, 그리고 특정 이벤트가 발생할 때, 해당 배열에서 요소의 추가와 제거가 발생한다고 가정하자.
본디 새로운 요소가 추가된다면, 새로이 추가된 요소는key
값으로 이전에 있었던 어느 요소와도 구분된 고유한 값을 가져야 한다. 제거의 경우에도 마찬가지로, 제거된 요소로 인하여 다른 요소의key
값이 변화해서는 안 된다.
그러나key
값을index
로 할당할 경우, 매핑의 과정에서 변경된 배열을 기준으로 다시금key
값이 할당된다.
이렇게 되면 원하지 않는 결과 값을 출력하게 된다.
그렇다면 어떤 데이터를key
값으로 활용해야 할 까? 이전 데이터베이스 세션에서 경험했던 바로는, 각 데이터에는 대체로id
값이 존재한다. 해당id
값은 데이터베이스 내의 고유한 값으로key
값에 적합하다고 볼 수 있다.
하지만index
를key
값으로 활용할 수 있는 경우도 존재한다. 해당 조건은 다음과 같다.
- 배열과 각 요소가
static
이며computed
되지 않고 변하지 않아야 한다.- 데이터 내부에
id
로 쓸만한unique
값이 없을 경우- 데이터가 결코
reordered
orfiltered
되지 않을 경우
올바른 key
의 사용
key
란 반복되는 컴포넌트를 서로 구분할 수 있는 고유한 값이다. 그렇기에 위에서 언급한 index
를 key
값으로의 사용을 지양하는 것도 이에 포함되는 것이다.
또한, key
값은 형제 요소 사이에서만 고유한 값이지, 전 범위에서 고유할 필요는 없다. 데이터베이스에서 각 테이블 내에 해당하는 고유 값이 존재하지만, 해당 값이 테이블 간의 고유 값이 겹칠 수 있다는 부분에서 확인할 수 있다.
그리고 위에서 확인했던 DOM 트리 구조를 다시 보자.
각 li
요소에 key
값이 명시적으로 표현되지 않음을 확인할 수 있다. React 에서 key
는 힌트를 제공하지만 컴포넌트로 전달하지 않는 부분을 이 부분에서 확인할 수 있다.
그렇기에 key
와 동일한 값을 명시적으로 표시하고 싶다면, 다른 이름의 prop
으로 전달하여 표현한다.
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
위 예시에선 key
값과 동일한 값을 명시적으로 id
라는 prop
에 할당하여 표현하였다. 앞의 codepen 예시에 똑같이 id
값을 추가하면 다음과 같은 결과를 확인할 수 있다.
🔖 참고
리액트 공식 문서 : 리스트와 Key
벨로퍼트와 함께하는 모던 리액트 : 배열 렌더링하기
Robin Pokorny : Index as a key is an anti-pattern
sjk5766님 Medium : [React] 배열의 index를 key로 쓰면 안되는 이유
Author And Source
이 문제에 관하여([TIL] React : List & Key), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@acidity/TIL-React-List-Key저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)