안녕하세요. 코딩하는 곰돌이입니다.
오늘은 리액트에서 map()을 사용해 배열을 렌더링 할 경우 key props가 필요한 이유에 대해서 정리해보고자 합니다. 우선 예시 코드부터 살펴보겠습니다!
예시코드
import React, { useState } from "react";
export default function TodoSample() {
const [todos, setTodos] = useState([]);
const [todoInput, setTodoInput] = useState("");
const onInput = (e) => {
setTodoInput(e.target.value);
};
const onAdd = () => {
setTodos([todoInput, ...todos]);
setTodoInput("");
};
return (
<>
<div>
<div>
<input type="text" onChange={onInput} value={todoInput} />
<button onClick={onAdd}>할 일 추가</button>
</div>
<ol>
{todos.map((todo, index) => (
<li>
<span>{todo} </span>
<input placeholder="메모를 입력하세요" />
</li>
))}
</ol>
</div>
</>
);
}
위 코드에 대해서 간단히 설명하자면 할 일을 추가하고 할 일에 대해 메모를 남길 수 있는 간단한 웹 사이트를 react로 코딩한 것입니다. 여기서 더 최근에 추가한 할 일이 위에 보이도록 코딩을 해줬습니다.
배열 렌더링 시 key props를 넣어주지 않을 경우
이제 실행화면을 크롬 개발자 도구와 함께 보도록 하겠습니다.
네 현재 앱을 실행하고 '할 일1'이라는 할 일을 추가한 상태인데요, 개발자 도구의 콘솔을 보시면 리스트의 각각의 자식 요소는 고유한 key prop이 있어야 한다고 뜹니다. 그럼 왜 이런 warning창이 뜨는 거고 왜 각 자식요소는 고유한 key prop을 가져야 하는 걸까요?
리액트는 DOM요소를 구분하기 위하여 key라는 props를 사용합니다. 이는 리액트 내부적인 트리 비교 알고리즘의 구현과도 상관있는 내용인데 이에 대한 자세한 내용은 나중에 기회가 된다면 다루도록 하겠습니다.
위에서 제시한 코드와 같이 map을 이용해 배열를 렌더링할 경우 key 값을 주지 않으면 알아서 배열의 인덱스를 key로 설정해줍니다. 보통 이렇게 넣어줘도 큰 문제가 되지 않는 경우도 많지만 다음과 같은 상황에서는 문제가 발생합니다. 한 번 할 일 1에 메모를 추가하고 할 일 2를 추가해주도록 하겠습니다.
직접 해보니 원하는대로 동작하지 않는 것을 알 수 있습니다. 왜 이렇게 된걸까요? 보시면 '할 일2'를 추가한 순간 todos라는 배열과 리액트 dom은 아래와 같아집니다.
// 이전
todos = ['할 일1']
<li key=0> //실제 dom에 key는 없음
<span>할 일1 </span>
<input placeholder="메모를 입력하세요" value='할 일1에 대한 메모'/>
</li>
// 이후
todos = ['할 일2', '할 일1']
<li key=0> //실제 dom에 key는 없음
<span>할 일2 </span>
<input placeholder="메모를 입력하세요" value='할 일1에 대한 메모'/>
</li>
<li key=1>
<span>할 일1 </span>
<input placeholder="메모를 입력하세요" />
</li>
리액트는 여기서 할 일2에 대한 input에 value가 옮겨간 이유를 이해하시겠나요? 리액트가 어떻게 변화를 감지하였는지 좀 더 구체적으로 살펴보겠습니다.
<li key=0>
<span>할 일2 </span> // 할 일1 -> 할 일2로 바뀜
<input placeholder="메모를 입력하세요" value='할 일1에 대한 메모'/>
</li>
<li key=1> // 할 일1에 대한 요소가 추가됨
<span>할 일1 </span>
<input placeholder="메모를 입력하세요" />
</li>
즉, 리액트는 할 일2에 대한 요소가 추가되었다고 인식하는 것이 아닌 key=1인 요소가 추가되고 key=0인 요소의 내부 text가 바꼈다고 인지하는 것입니다. 그럼 정상적으로 동작하려면 어떻게 바꿔줘야 할까요?
문제의 해결법
바로 key를 요소를 식별할 수 있는 고유한 값으로 변경해주면 됩니다.(여기서는 할 일의 이름이 고유하다고 가정하겠습니다)
<li key={todo}>
<span>{todo} </span>
<input placeholder="메모를 입력하세요" />
</li>
이렇게 key를 추가해주면 원하는 대로 동작하는 것을 알 수 있습니다.
결론
이렇듯 일반적으로 크게 신경쓰지 않는 key props가 어떤 문제를 일으키고 어떻게 이런 문제를 해결해야 하는지에 대한 내용을 지금까지 살펴보았습니다. 지금처럼 기능상의 문제 때문에 key props를 추가해줘야 하는 경우도 있지만 렌더링 성능을 위해서라도 key props를 고유한 값으로 넣어주는 것은 중요하기에 가능하다면 항상 key props를 배열 요소의 고유 식별자로 넣어주는 것이 중요합니다.
지금까지 코딩하는 곰돌이었습니다.
'개발 공부 > WEB' 카테고리의 다른 글
[웹사이트 직접 만들기] 웹사이트를 만드는데 필요한 지식 - 1 (HTML) (0) | 2022.04.30 |
---|---|
[React] <></>에 key props 추가하는 방법 (0) | 2022.03.30 |
[React] setState가 바로 적용되지 않는 이유 (1) | 2022.02.12 |
[Next.js] Data Fetching을 하는 4가지 방법 (0) | 2021.12.21 |
[주니어 개발자의 퇴근 후 글쓰기] Spring Framework (0) | 2021.12.07 |