프론트 개발하다 보면 array를 뷰에 표시할 때마다 시뻘건 오류로 unique key props를 설정하라는 워닝을 보게 된다.
backend에서 unique키 안주면 대충 index나 nanoid로 때우던 본인은 이번에 key props관련으로 꿀잼 이슈를 겪게 되었다.
1. 문제 상황
아래와 같은 코드를 사용하여 테이블을 렌더링 하고 있었다
<code />
<tbody>
{futuresCoinData.map((coin) => (
<tr key={nanoid()} className="text-sm font-medium text-black">
<td className="flex items-center gap-1 py-2">
<SubscribeStarOn />
<span
className="cursor-pointer"
onClick={() => {
changeSymbol(coin.name);
}}
>
{coin.name}
</span>
</td>
</tr>
))}
</tbody>
위 코드에서 nanoid()를 사용하여 각 <tr> 요소에 고유한 키를 부여하고 있다.
changeSymbol이 6번정도 눌린 후엔 꼭 한 번씩 입력이 씹히는 이슈가 발생했다.
2. 원인 분석
changeSymbol에서 mobx when()이 비동기 작업을 block 하는 등 얽힌 작업이 많아 하나하나 콘솔을 찍어봤다.
근데 다 겁나 잘 되는데 2초후부터 꼭 한 번씩 씹히는 것이었다. 머리털 뽑으면서 찾아본 결과 key props문제였다는 걸 깨달았다.
React에서 key 속성은 리스트의 각 요소를 고유하게 식별하기 위해 사용된다. 중요한 점은 이 키가 렌더링 사이에서 안정적이고 고유해야 한다는 것이다. 그러나 nanoid()를 사용하면 매번 새로운 ID가 생성되므로, 컴포넌트가 리렌더링될 때마다 키 값이 변경된다.
이로 인해 React는 기존의 노드를 재사용하지 않고, 모든 <tr> 요소를 언마운트한 후 새로 마운트 한다. 결과적으로 이벤트 핸들러가 연결된 기존의 요소들이 제거되고, 새로운 요소들에 이벤트 핸들러가 연결된다.
2초 후부터 한번씩 씹히는 이유는 2초 tick rate마다 ws 메시지로 온 coin price를 개별 업데이트 해주다 보니 제대로 key값을 연결해 주지 않아 재조정과정에서 노드를 새로 만들고 그 오버헤드로 인해 이벤트리스너가 잘못 연결되어 onClick이 호출되지 않았던 것이다; 어쩐지 콘솔도 안 찍히더라
3. 해결 방법
3.1. 안정적인 키 사용하기
문제를 해결하기 위해서는 안정적이고 고유한 키를 사용해야 한다. 데이터에서 고유한 값을 찾아 key로 사용하면 된다. 예를 들어, coin.name이 고유한 값이라면 다음과 같이 수정할 수 있다:
<code />
<tbody>
{futuresCoinData.map((coin) => (
<tr key={coin.name} className="text-sm font-medium text-black">
<td className="flex items-center gap-1 py-2">
<SubscribeStarOn />
<span
className="cursor-pointer"
onClick={() => {
changeSymbol(coin.name);
}}
>
{coin.name}
</span>
</td>
</tr>
))}
</tbody>
4. 결과
이렇게 키를 안정적인 값으로 변경하면, React는 각 요소를 올바르게 추적하고 재사용한다. 따라서 불필요한 언마운트와 마운트가 발생하지 않으며, 이벤트 핸들러도 정상적으로 동작한다.
5. 결론
하지 말란 건 이유가 있다. 엄마 잔소리같이 다 잘되라고 하는 말이니 에러 메시지를 유의 깊게 보도록 하자. 이상하게 key 설정하는건 귀담아 듣지 않았는데 결국 몸으로 겪게 되었다 ㅋㅋ..
구현 스펙에 맞춰 불변값을찾아 적절히 key에 넣도록 하자
내 능지미달 행동을 통해 사수분께 큰 웃음을 선사해 드렸다…
'<frontend>' 카테고리의 다른 글
form 바깥에서 submit시키는 button 구현하기 (0) | 2025.02.22 |
---|---|
javascript 비동기 순서보장 잡기술 (0) | 2024.09.29 |
트레이딩뷰 무료 고급 차트 라이브러리 신청&사용 (1) | 2024.09.29 |
styled-component -> tailwindcss migration reset css (4) | 2024.08.01 |