개발

반복되는 컴포넌트 key에 index를 넣으면 안되는 이유

배우겠습니다 2024. 1. 3. 21:12

요구사항

유저의 타입(일종의 특성이다)라는 최대 3개까지 설정 가능한 데이터가 있었다.

유저가 설정한 개수를 t라고 할때 1~t번째 까지는 타입에 해당하는 이미지를 보여줘야 했고 t+1~3번째까지는 +버튼을 보여줘야 했다.

 

사실 비즈니스 우선순위가 제일 후순위라 이쪽 코드를 방치해두고 있다가 최근에 이와 관련된 백엔드 api가 완성돼서 적용했다.(UI적으로도 변경될 가능성이 높은 부분이다 나중에 갈아엎을 예정이려나..?)

 

처음에 내가 짠 코드

myType이라는 데이터를 받는다.

i를 0부터 3-1까지 순회하며 i < myType.length라면 타입 이미지를 보여주고, i >= myType.length라면 +버튼을 보여주는 코드를 짰다.

여기서 +버튼의 key는 단순히 i로 줬다.

// indexArr은 단순히 길이가 3인 배열이다.
{indexArr.map((e,i) =>
          i < data.length ? <TypeInfoCard data={data[i]} key={data[i].id}/> : <TypeAddCard setIsOpen={setIsOpen} key={i} flag={flag}/>,
        )}

 

대충 ui만 구성하자는 생각으로 이렇게 짰으나, 매우 잘못된 코드이다.

 

문제 상황

타입 설정(수정)모달에서 타입을 수정한다면, 길이가 들쭉날쭉해졌다.

3개만 설정했는데 이전에 설정한 데이터까지 포함돼서 TypeInfoCard가 랜더링되는 문제가 있었다.

 

문제 원인

백엔드에서 준 data[i].id는 0~12사이의 순서대로 증가하는 number였다.

인덱스기반의 id는 data[i].id와 겹치는 상황이 충분히 발생한다. 

key는 리액트가 반복되는 component list에서 element를 추적할때 쓰이는데, TypeAddCard의 key에 인덱스 기반의 id를 줘서 리액트가 element를 잘못 추적하는 상황이 발생했다.

 

문제 해결

const indexArr: {id:string}[] = [{id:'sad'}, {id:'gfd'}, {id:'fkf'}, {id:'ekw'}]

{indexArr.map((e,i) =>
          i < data.length ? <TypeInfoCard data={data[i]} key={data[i].id}/> : <TypeAddCard setIsOpen={setIsOpen} key={e.id} flag={flag}/>,
        )}

 

indeArr에 이상한 문자열을 줘서 id가 겹치는 문제를 발생하지 않도록 했다.