리액트에서 여러 element들을 반환할 때는, 각각의 element 마다 고유한 key를 넣어줘야 한다.
만약 key 값을 넣어주지 않으면 렌더링에는 문제가 없지만 아래와 같은 에러가 나타난다. 👿
여태 그저 경고 메시지를 지우기 위해 key값을 넣어주었다면 앞으로는 알고 쓸 수 있도록 하자!
Key 값을 넣어줘야 하는 이유
위와 같이 항목을 추가할 수 있는 list를 만들어 알아보자!
추가할 항목 적어 추가 버튼을 눌러주면 , 우측의 개발자 도구에서 모든 li태그가 깜빡거리는 걸 볼 수 있다.
깜빡였다는 것은 DOM상에서 업데이트되었다는 뜻이다.
우리는 리스트 맨 위의 항목 하나만 추가했을 뿐인데 모든 요소들이 업데이트되었다는 것을 알 수 있다.
-> 그 이유는 key 값을 주지 않았기 때문에 리액트는 어떤 요소가 업데이트되었는지 알 수가 없다!
이렇게 항목 하나가 추가될 때마다 모든 항목이 업데이트된다면 아주 비효율적이다 🧐
그렇다면 key값을 추가해보자!
<ul>
{list.map((item) => {
return <li key={item}>{item}</li>;
})}
</ul>
이번에는 새롭게 추가된 항목만 깜빡거리는 것을 알 수 있다.
앞서 키값이 없었던 예시 상황과는 다르게 item이라는 키값을 가지고 있기 때문에, 추가해 준 요소 외에는 업데이트가 되지 않은 것이다.
주로 하는 실수 - index를 key값으로
map 함수는 두번째 인자로 index를 받기 때문에 많은 개발자들이 key 값으로 index 값을 주곤 한다.
하지만 리액트 공식문서에서도 볼 수 있듯이 key 값으로 index로 주는 것을 🚨 지양 🚨 하라고 한다.
왜 지양해야 하는지 직접 알아보자!
<ul>
{list.map((item, index) => {
return <li key={index}>{item}</li>;
})}
</ul>
이렇게 key값을 index로 주고 새로운 항목을 추가해 보면,
'코딩하기'라는 새로운 항목을 추가하니 모든 요소들이 깜빡이는 것을 볼 수 있다.
그 이유는 index라는 값은 안정적이지 않기 때문이다.
새로운 항목을 추가하기 전, 운동하기는 0번째 인덱스 공부하기는 1번째 인덱스를 가지고 있는데
새로운 항목이 추가되면 코딩하기가 0번째 요소가 되기 때문에 운동하기와 공부하기는 더 이상 그 전의 인덱스 값이 아니게 된다! 그렇기 때문에 index를 key값으로 사용하는 것은 안정적인 방법이 아니다.
만약에 화면에 출력되는 리스트의 값이 변하지 않는 정적인 리스트라면, index값을 key값으로 사용해도 문제가 되지 않는다. 하지만 예시 리스트처럼 항목이 변경되는 리스트라면 안정적인 key값이 아니라는 점!!!
index key값의 버그🐛
<ul>
{list.map((item, index) => {
return (
<div key={index}>
<li>{item}</li>
<input />
</div>
);
})}
</ul>
리스트 밑에 input 칸을 추가한 후에 index를 key값으로 사용하면 어떤 상황이 벌어지는지 확인해 보자!
이렇게 리스트 밑에 알맞은 input 내용을 작성해 주었다. 그리고 새로운 항목을 추가하면?
'안녕'이라는 항목을 추가했는데 input안의 내용의 순서가 바뀐 것을 볼 수 있다.
<ul>
{list.map((item, index) => {
return (
<div key={item}>
<li>{item}</li>
<input />
</div>
);
})}
</ul>
그렇다면 이번에는 key값을 item으로 바꿔보자.
내용 바뀜 없이 정상적으로 잘 나오는 것을 볼 수 있다.
이런 버그 같은 상황이 벌어지는 이유는 index같이 안정적이지 않은 key값을 사용했기 때문이다.
고로 key값은 고유하고 안정적이여야 한다!
key값이 중복된다면❓
<ul>
{list.map((item) => {
return <li key={item}>{item}</li>;
})}
</ul>
키값을 item으로 설정해 두고 , 키값이 중복되면 어떻게 될까?
이렇게 같은 item 값을 가진 항목이 중복되면 에러가 나타난다.
그 위에 또 다른 '코딩하기' 항목을 추가했을 뿐인데 작성하지 않은 '운동하기'라는 항목이 또 생긴 버그 같은 상황이 발생한다.
-> 경고창의 메시지를 보면 중복된 key를 가지고 있으면 자녀가 복제될 수 있고 업데이트가 정상적으로 되지 않을 수 있으며 리액트는 아직 이 경우에 대비하지 않는다고 한다. === 고유한 key값을 사용해야 한다!
이를 해결하기 위해서
import { useState } from "react";
function App() {
const [inputValue, setInputValue] = useState("");
const [list, setList] = useState([
{
id: "1",
value: "운동하기",
},
{
id: "2",
value: "공부하기",
},
]);
const addToList = () => {
setList((prevList) => {
return [
{
id: list.length + 1 +"",
value: inputValue,
},
...prevList,
];
});
setInputValue("");
};
return (
<div style={{ marginTop: "20px" }}>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
></input>
<button onClick={addToList}>추가</button>
<ul>
{list.map((item) => {
return <li key={item.id}>{item.value}</li>;
})}
</ul>
</div>
);
}
export default App;
state의 값을 문자열이 아닌 객체로 변경해 주고, key값도 item.id로 작성해 준다.
++ id: list.length + 1 + '' 처럼 ''를 더해줘서 id 값을 숫자가 아닌 문자열로 바꿔준다!
이렇게 해주면 경고창 없이 성공적으로 고유한 key값을 주어 동적으로 값을 추가하는 리스트를 만들 수 있다!
✨별코딩님의 List와 Key와 중요성을 수강하면서 정리한 내용입니다. ✨
혹시나 잘못된 내용이나 부족한 부분에 대한 피드백은 언제나 환영입니다!
'React' 카테고리의 다른 글
React 기초 A-Z 🔎 (0) | 2024.06.05 |
---|---|
React Hooks🪝useEffect (0) | 2024.05.31 |
React Hooks🪝useState (0) | 2024.05.27 |
React 프로젝트 세팅하기 +CRA, typescript (0) | 2024.05.24 |
리액트의 가상돔 (Virtual DOM) (0) | 2023.11.08 |