key는 React가 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는다. key는 element에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정해야한다.
배열을 예로 들로 들어봅시다. 3개의 리스트가 있다고 가정할 때 key값이 없다면 리스트가 추가 된다고 가정할 때 총 4개의 리스트를 리렌더링하게 됩니다. 하지만 Key를 지정한다면 기존의 요소가 변경되지 않았다는 걸 React가 파악하며 새로 생기는 요소에 대해서만 리렌더링을 진행하게 됩니다.
정리 - 각 고유 원소에 key 가 있어야만 배열이 업데이트 될 때 효율적으로 렌더링 될 수 있기 때문이다.
key값을 index로 지정하고 배열에 요소를 앞에 추가한다고 가정하면 배열이 새로 바뀌게 되면서 컴포넌트가 리렌더링이 되고 이때 index를 다시 매핑하게 됩니다. 이 때 항목의 순서가 바뀌고 key값 역시 바뀌게 되어 예상과 다른 리렌더링을 보여줄 수 있다.
따라서 key에 index를 사용하는 경우는 아래와 같은 한정적인 경우에만 사용하는 것이 좋다.
- 배열과 배열의 항목들이 static 하여 변경되지 않는 경우
- 배열의 항목들이 id 값이 없는 경우
- 배열이 절대 재배열되거나 일부가 삭제되지 않는 경우
결론 - React에서는 불변성이 지켜지지 않으면 객체 내부의 값이 새로워져도 바뀐것을 감지하지 못한다
불변성은 어떤 값을 직접적으로 변경하지 않고 새로운 값을 만들어내는 것이다. 만약 원시타입이 아닌 객체타입의 데이터를 어떠한 변수에 할당하고 그 변수를 다른 변수에 다시 할당했다면, 배열의 복사가 이루어지는 것이 아니라 같은 참조값을 갖게 된다. 따라서 불변성을 지켜내지 못해 React에서 변경을 감지하지 못해 리렌더링을 하지 않게되는 문제점이 발생한다.
질문 ------ onClick={() => onRemove(user.id)} 이 코드는 잘 동작하는데 onClick={onRemove(user.id)} 이 코드는 왜 동작하지 않는건가요?
답변 ----- onClick={someFunction()} 을 해버리면 해당 콤포넌트가 렌더링이 되는것과 동시에 someFunction함수를 실행시켜버립니다.
그래서 보통 onClick={someFunction} 으로 지정해서 () 를 제외하는 방법으로 함수가 즉시실행 되지 않게 하고, 클릭했을때 실행이 되도록 해주죠
그런데 예제와 같이 onRemove의 경우, 해당 함수가 실행될 떄 아이디 값도 받아와야 하잖아요. 이런 경우에 onClick = { onRemove(user.id) } 를 해버리면, 해당 콤포넌트가 렌더링됨가 동시에 이 함수 실행이 되어버려서 아마 아무것도 렌더링이 되어버리지 않을거에요. 콘솔에서도 오류메시지가 발생할거구요.
따라서 이런 문제들을 해결하기 위해 onClick에 콜백 함수를 넣어주고, 해당 함수가 실행될 때 user.id를 건네주어 실행시키는 방법으로 처리를 하는거에요.