반복되는 컴포넌트를 만들어줄때 해당 데이터 가진 id를 key로 사용했는데 자꾸 유니크한 키 값을 사용해달라는 경고가 떴다.
api에서 반환해주는 데이터 중에서 반환해주는 값이 _id인 것이 있어서 게시물 컴포넌트의 key값을 줄때도 착각하여 _id로 주었던 것이 원인이였다. 키 값을 분명히 주었는데 안 줬다고 한 이유는 key={post.id}로 주어야했는데 {post._id}로 준 것이다.
혹시 이러한 일이 반복될까봐 id를 키 값으로 전달해주는 것은 오타에 의한 실수를 불러일으킬 수 있다고 생각하여 고유한 키 값을 만드는 방법이 없을까 고민하였다. 찾아보니 Crypto.randomUUID()를 통해 난수 아이디를 생성하여 넣어주는 것이였다.
하지만 key에 대해 공식문서를 살펴보면 'Key를 선택하는 가장 좋은 방법은 리스트의 다른 항목들 사이에서 해당 항목을 고유하게 식별할 수 있는 문자열을 사용하는 것입니다. 대부분의 경우 데이터의 ID를 key로 사용합니다.' 라고 적혀져 있다.
추가적으로 리액트는 컴포넌트를 렌더하면서 어떤 변화가 있었는지를 비교하는 알고리즘(Diffing Algorithm)을 가지고 있다.
render 함수는 이 알고리즘을 이용하여 기존 React 엘리먼트 트리와 비교하고 새로운 React 엘리먼트 트리를 생성해서 반환한다.
기존 트리를 가지고 다른 트리로 변환하기 위해 최소한의 연산을 하는 알고리즘 문제를 해결하기 위해 일반적으로 O(n^3)의 시간 복잡도를 가진다. 이대로 리액트에 적용한다면,새로운 트리를 그릴때 너무 많은 연산이 필요하게 된다고 리액트 공식문서에 나와있다.
따라서, 리액트에는 두 가지 가정을 통한 휴리스틱 알고리즘을 적용하여 이 연산을 O(n)까지 줄일 수 있었다고 설명한다.
서로 다른 타입의 두 엘리먼트는 서로 다른 트리를 만들어낸다. 개발자가 key prop을 통해, 여러 렌더링 사이에서 어떤 자식 엘리먼트가 변경되지 않아야 할지 표시해 줄 수 있다.
이 때, 사용되는 것이 key prop이다. 리액트에서는 key prop을 통해 컴포넌트를 새로 렌더하면서 엘리먼트 트리를 생성할 때, 더 빠르게 비교 연산을 수행하고 렌더할 수 있다.
때문에 배열의 순서에 따라 변경되는 index를 key값으로 주거나, random한 아이디를 key값으로 주게 되면 새로 컴포넌트를 그릴때 이전에 있던 key값과 비교했을때 기존 컴포넌트와 다르다고 판단하여 불필요한 연산이 일어나게 된다.
따라서 변하지 않는 고유한 id를 키 값으로 주는 것이 맞다고 생각했다.