react-beautiful-dnd 이슈

불꽃남자·2022년 8월 15일
0

개요

최근 Drag And Drop(이하 dnd) 기능을 구현해야 할 일이 있어 react-beautiful-dnd 라는 라이브러리를 배우고 사용 중에 있다.
이 라이브러리는 현재 나와있는 dnd 라이브러리 중에서는 가장 사용하기 쉽고 필요한 기능도 다 있는 라이브러리라고 평가된다.

이 라이브러리를 사용중에 이슈가 발생했는데, 컴포넌트가 랜더링 되고 나서 처음엔 dnd 기능이 정상적으로 작동하는데, 두 번째 부터는 dnd 기능이 작동하지 않는 것이다.
콘솔로그엔 다음과 같은 에러 메시지가 출력되고 있었다.

unable to find draggable with id
아마도 dnd를 통해 리스트 컴포넌트의 순서를 바꾼 뒤에 리스트 컴포넌트를 추적하지 못 하고 있는 것 같다.

		<DragDropContext onDragEnd={onDragEnd}>
          <Droppable droppableId="interviewTemplate">
            {provided => (
              <div {...provided.droppableProps} ref={provided.innerRef}>
                {templates.map((template, index) => {
                  return (
                    <Draggable
                      draggableId={template.interviewTemplateId}
                      index={index}
                    >
                      {provided => {
                        return (
                          <Container
                            ref={provided.innerRef}
                            {...provided.draggableProps}
                            {...provided.dragHandleProps}
                          >
                            <p>{template.title}</p>
                          </Container>
                        );
                      }}
                    </Draggable>
                  );
                })}
                {provided.placeholder}
              </div>
            )}
          </Droppable>
        </DragDropContext>

모든 게 공식문서대로 적용되었는데, 뭐가 문제였을까?

map 함수가 반환하는 ReactElement의 key prop

정답은 바로 map 함수가 반환하는 ReactElement의 key prop을 넣지 않아서이다.
나같은 경우 map 함수가 반환하는 Draggable 컴포넌트에 key prop을 넣었더니 제대로 작동했다.


이제 잘 작동한다

왜 key prop을 주지 않은 것 만으로 이런 이슈가 발생했을까?
그걸 알기 위해선 react의 list에서 key prop의 역할 에 대해 알 필요가 있다.

key prop의 역할

위의 링크로 접속해보면, react 공식문서에서 이에 대해 설명하고 있다.

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

예를 들어 위의 리스트에서 아래의 리스트처럼 순서를 변경했을 때, React는 rerendring을 할 것이다. 그래야 뷰포트에 바뀐 리스트의 순서가 반영될테니까.
그런데 위와 같이 리스트의 첫 번째 순서에 새로운 컴포넌트가 추가된 경우에, 리스트의 순서도 바뀌게 되고, 결과적으로 React는 모든 컴포넌트를 rerendering 한다. 실상은 그저 리스트의 순서만 바뀐 것인데 말이다.

이런 비효율적인 상황을 해결하기 위해서 key prop이 사용된다.

<ul>
  <li key={2015}>Duke</li>
  <li key={2016}>Villanova</li>
</ul>

<ul>
  <li key={2014}>Connecticut</li>
  <li key={2015}>Duke</li>
  <li key={2016}>Villanova</li>
</ul>

이렇게 key prop을 추가하면, 리스트의 순서가 바뀌었을 때 React는 먼저 key prop을 통해서 리스트 컴포넌트를 식별한다. 리스트 순서가 바뀌기 전과 바뀐 후의 컴포넌트의 key prop을 비교하고, 일치한다면 같은 컴포넌트로 판단하고 rerendering 하지 않고 컴포넌트의 순서를 이동만 시킨다는 것이다.

그렇기 때문에 key prop은 고유해야한다. 간혹 map 함수의 콜백함수의 2번째 인자인 index를 key prop의 값으로 주는 코드도 있는데, 그랬다간 코드가 예상치 못한 방향으로 작동할 수 있다. index 값은 리스트의 순서가 변경되면 바뀔 수 있기 때문에.


이제 key prop이 react-beautiful-dnd 라이브러리의 작동방식에서 어떤 역할을 하는지 대충은 알 수 있다.
아마도 key prop을 주지 않았을 때, 내가 위의 gif처럼 dnd를 통해 리스트의 순서를 바꾸면 리스트 전체가 rerendering 되면서 react-beautiful-dnd 라이브러리가 리스트 컴포넌트를 추적하지 못 하게 되는 것 같다. 비록 기본적으로 draggableId prop을 통해 컴포넌트를 추적하더라도 말이다.

리스트에서의 key prop의 역할에 대해서는 이미 이전에 알아보고 배운 적이 있다. 그럼에도 불구하고 그 중요성에 대해 간과했기 때문에 일어난 이슈다.
key prop이 중요하지만, 특히 리스트의 순서를 바꾸는 때에는 훨씬 더 중요하다는 걸 주의해야겠다고 생각한다.

profile
프론트엔드 꿈나무, 탐구자.

0개의 댓글