React-SortableJS 대신 SortableJS 적용하기

yj j·2024년 2월 15일
post-thumbnail

리액트로 처음으로 만들어본 프로젝트는 투두리스트였습니다.
리스트에 있는 할 일의 순서를 바꿀수 있게 만들기 위해 SortableJS 라이브러리를 사용하려고 했을 때 삽질했던 기록입니다.
리액트에 대해 아무것도 몰라서 해결하지 못했던 몇 주 전의 문제를 꼭 풀어보고 싶었습니다.

프레임워크에 종속된 라이브러리부터 검색하지 말고, 자바스크립트로 된 라이브러리부터 먼저 쓰는게 좋다고 배웠는데요!
그 이유는 리액트에서도 바닐라 자바스크립트 라이브러리만으로 충분히 구현이 가능한 데다가 상대적으로 의존성이 낮아지기 때문에 안정성 측면에서도 좋습니다.

많이 이용하는 라이브러리가 업데이트가 계속 될 확률이 높습니다.
지금 당장은 돌아갈지 모르겠지만, 나중에는 돌아가지 않을 수도 있는 확률을 최대한 낮추고자 하는 것입니다.

SortableJS와 react를 위한 react-sortableJS의 이용자 기록을 npm 사이트에서 비교해봤습니다.
실제로 주간 다운로드 수가 7배 이상 차이가 나고, SortableJS가 업데이트도 훨씬 더 활발합니다.

그래서 처음에는 순수한 SortableJS만으로 구현을 하고 싶었는데, 다양한 난관이 있었던 것 같습니다.

SortableJS의 README에 있는 예시입니다.

var el = document.getElementById('items');
var sortable = Sortable.create(el);

예제는 document.getElementById로 실제 DOM으로 접근하는 코드입니다.

실제 DOM으로도 접근이 가능하지만, 리액트에서는 이런 식의 접근은 지양합니다.
리액트는 라이프사이클에 맞춰 DOM Element를 가져오기 때문에, 직접 DOM을 건드리게 되면 리액트의 제어를 벗어나게 되면서 디버깅이 어려워지기 때문입니다.
되도록이면 좀 더 정석적인 방법을 쓰고 싶었습니다.

리액트는 이렇게 특정한 DOM을 선택해야 하는 상황에서는 ref를 사용해줍니다.
그래서 처음에 작성한 코드는 이러했습니다.

	  let el = useRef();
      Sortable.create(el.current);
	  return (
      <ul className="sortable-list" ref={el}>
        <li>1</li>
        <li>2</li>
        <li>3</li>
      </ul>
      );

Uncaught Sortable: `el` must be an HTMLElement, not [object Undefined]

userRef로 선택한 DOM이 HTMLElement가 아니라고 뜹니다.
당시에 저는 가상 DOM은 JSX element라는 생각이 강했기 때문에, HTML element가 아니기 때문에 오류가 나는 것이라고 생각하고, 바로 적용이 가능했던 react-sortableJS를 사용해 드래그 앤 드랍이 가능한 리스트를 만들었습니다.

JSX element는 HTML element라고 할 수 없을까요?

그렇다면, HTMLElement은 어떻게 정의했는가?! 어떻게 하면 유발되는 에러인가 판단하고자 했습니다.

해당 라이브러리에서는, 매개변수 el을 엘리먼트의 nodeType이 존재하고, 그 타입이 Element node를 의미하는 1인 것으로 정의했습니다.
ref로 가리킨 el에 대한 결과는 다음과 같습니다.

  let el = useRef();
  console.log(el.current.tagName);  //UL
  console.log(el.current.nodeType); //1

nodeType이 멀쩡히 1이 나오고 있습니다. 태그네임 또한 판단하고 있습니다.
그러면 이 검증을 제대로 통과하지 못했던 이유가 무엇일까요?

저의 가장 중대했던 실수는 컴포넌트의 생명주기를 고려하지 않았다는 것입니다.
DOM을 제대로 가리키려면 DOM이 마운트된 시점이어야 했습니다.

아래의 코드로 작성하니 의도한 대로 실행됩니다.

  let el = useRef();
  useEffect(() => {
    Sortable.create(el.current);
  }, []); //마운트 된 시점


리액트를 처음 배웠을 때 해결하지 못했던 문제를 몇 주 뒤에 다시 보게 되었고, 지금도 반나절 정도는 머리를 쥐어싸매긴 했지만 정말 궁금증이 해결이 된 게 신기하고 뿌듯하네요.

예전엔 해결하지 못했던 문제를 잘 기록하고 돌아보는 습관을 가져봐야겠습니다!

JSX element도 html element냐, 라는 근본적인 의문은 정확하게 해소하기가 어려웠지만 DOM을 직접 지정하는 ref의 활용도를 봐서는 통용된다는 느낌이 강한 것 같습니다.
어쨌든 리액트도 자바스크립트니까요! 리액트가 어떤 식으로 동작하는지 알아보고 싶어졌네요.

리액트의 생명 주기도 제때 잘 판단해서 쓰는 것을 목표로 해야겠습니다!

profile
꿈꾸는 사람

0개의 댓글