React18의 strictMode와 react-beatiful-dnd

Sal Jeong·2023년 2월 22일
1

현재 진행하고 있는 프로젝트에서 DND 기능을 다시 만들어볼 기회가 생겼는데, 계속해서 DroppableId를 찾지 못하는 에러가 발생했다.

TR&DR

requestAnimationFrame을 불러 paint 이후에 Droppable을 등록하면 StrictMode를 해제하지 않아도 사용할 수 있다.

문제 자체는 쉽게 찾을 수가 있었는데,

현재 프로젝트의 리액트 버전 18의 StrictMode가 문제를 일으킨다는 것.

react 18의 StrictMode에서는 이전 버전들과 다르게 디버깅 목적을 위해 라이프사이클을 의도적으로 두 번 실행시키는데, 그 부분에서 등록된 Droppable의 ref 자체가 사라지는 이슈가 생겼던 것이었다.

* React mounts the component.
  * Layout effects are created.
  * Effects are created.
With Strict Mode in React 18, React will simulate unmounting and remounting the component in development mode:

* React mounts the component.
  * Layout effects are created.
  * Effects are created.
* React simulates unmounting the component.
  * Layout effects are destroyed.
  * Effects are destroyed.
* React simulates mounting the component with the previous state.
  * Layout effects are created.
  * Effects are created.
See docs for ensuring reusable state here.

React Docs에서는 version 18.의 StrictMode를 이렇게 설명하고 있다.

  1. useLayoutEffect -> useEffect ->
  2. layoutEffectCleanUp -> effectCleanup ->

이후 다시 useLayoutEffect와 useEffect를 실행하는데, 이때 사용하는 값은 1.에서와 동일한데, 이때 참조해야할 ref의 데이터가 2번을 거치면서 사라져서 DroppableId 자체를 찾을 수 없었던 것.

// use-droppable-publisher.js l.262
  // update is enabled with the marshal
  // only need to update when there is a drag
  useLayoutEffect(() => {
    if (!whileDraggingRef.current) {
      return;
    }
    marshal.updateDroppableIsEnabled(
      publishedDescriptorRef.current.id,
      !args.isDropDisabled,
    );
  }, [args.isDropDisabled, marshal]);

위 beatiful-dnd의 소스를 본다면, 1. useLayoutEffect의 내용에 Droppable을 등록하지만,
StrictMode의 2를 거치면서 ref의 참조가 사라짐 -> Droppable Id를 찾을 수 없음이 되는 것으로 보인다.

https://github.com/facebook/react/issues/24670
의 페이지에서도 같은 이슈를 찾을 수 있었는데, StrictMode에서 unmount / remount를 반복하는 과정에서 ref값이 사라지는 이슈이다.

첫 참조 페이지에서의 해결책은 다음과 같다.

layoutEffect로 등록 -> unmount / remount 시 ref값이 사라지기 때문에,
해당 unmount / remount 이후에 Drappable 자체를 등록하면 문제 없이 쓸수 있다.

따라서 requestAnimationFrame을 불러 paint 이후에 Droppable을 등록하면 StrictMode를 해제하지 않아도 사용할 수 있다.

하지만 다음에 Dnd기능을 요구받으면 다른 라이브러리를 사용하면 더 편할 것 같다.

https://dndkit.com/ 같은것들...

참조:

https://github.com/atlassian/react-beautiful-dnd/issues/2399

react-beatiful-dnd github

https://github.com/facebook/react/issues/24670

profile
행복하기 위해 코딩합니다. JS 합니다.

1개의 댓글

comment-user-thumbnail
2023년 5월 24일

정말 감사합니다.... 위 문제때문에 라이브러리 없이 구현해야 하나 고민하고 있었는데 삽질이었군요

답글 달기