ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ 리액트 ] react portal을 사용하여 react-beautiful-dnd 이슈 해결하기
    코딩/REACT 2020. 12. 3. 23:51

    리액트엔 뭐 여러기능들이 있는데

     

    요즘 사용된 기술만 사용했지 다른 것들은 배제하고 사용하고 있었습니다.

     

    그런데 최근에 beautiful-dnd라는 모듈을 사용하다가 

     

    이상한 이슈에 빠져서 해매던중에 portal 을 사용하라는 이야기가 있었습니다.

     

    포탈 많이 들어봤는데 제가 사용할 일은 없겠다 싶기도 하고, 굳이 알고 싶지도 않았었는데 

     

    당장 고치고싶은 마음이 굴뚝같아서 바로 뒤적여보게 되었습니다 ㅋㅋㅋ..(역시 사람이란...)

     

    포탈이란

     

    리액트 앱은 부모 컴포넌트에서 자식컴포넌트로 렌더링하게 되어있는 구조인데

     

    자식컴포넌트렌더링을 부모컴포넌트가 아닌 다른곳에서 렌더링할수있게끔 하게 해주는 기능입니다

     

    여러예제를 보니까 Modal 컴포넌트를 만들때 주로 사용하는거 같았습니다.

     

    여튼 왜 react-beautiful-dnd에 서 사용하게 되었냐면

     

    이모듈은 대표적으로 trallo같은 드래그 ㄷ앤 드롭을 쉽게 구현해주는 고마운 모듈입니다

     

    저보고 드래그앤드롭을 구현하라하면 고통속에서 허득였을텐데 단숨에 해결해준 친구죠

     

    사실 전 이친구를 실시간 검색어를 보여주는 view에서 사용하고 있었는데요

     

     

    캡쳐 이상하게 했네요 ;

    실 데이터 기반이지만

     

    1분사이에 저렇게 휙휙 바뀌진않고 ,순위도 맞지않답니다. 저건 제가 캡쳐 보여주기식으로

     

    셔플을 빡시게 해놔서  저렇게 다이나믹하게 보여지게 했습니다.

     

    좀 컴팩트하게 이동하면 좋을텐데 

     

    dnd상 하나를 움직이면 나머지가 밀리게 되어있어서 뭔가 어쩔수가 없었어요

     

    로직을 가장 많이 순위 변동이 심한것부터 이동하게 해놨습니다. 좀 정신없죠 ㅎㅎ

     

    제가 dnd 모듈에 대한 이해도가 없어서 프로그래미컬 예제를 하나 가져와서 

    주먹구구식으로 typescript로 변환하고 하나하나 지워가면서 사실 잘만들었다고 볼수는없어요..

    좀 복잡하답니다..ㅠㅠ....리팩토링해야할텐뎀...좀 귀찮네요.ㅎㅎ..ㅋㅋㅋ 

     

    그래도 1분정도로 패칭하면 나름 합리적으로 움직인답니다.~

     

    여튼 이게 뭔 문제냐 싶죠 그냥 쓰면 아무것도 문제가 되지않는데

     

    react-grid-layout 때문에 문제가 되었습니다.

    신기하죠?ㅎㅎ

    이 모듈은 컴포넌트를 제가 원하는 곳에 위치할수 있도록 해주는 모듈인데

     

    저게 transform 스타일을 element에 맥여서 위치시키는 원리더라구요

     

    그래서..안에 해당 하는 저 드래그 아이템들이 그 값이 먹여져서 드래그앤 드롭으로 이동할때...

     

    옆으로 이동하는 불상사가 발생하였습니다.

     

    f**K..

     

    이거를 해결하려고

     

    생각을 좀 해봤는데

     

    transform

     

     

    react-beautiful-dnd는 드래그 되어 있는지 아닌지를 알 수 있으니 

     

    각  검색어들에 ref를 내려주고 해당 transform된 만큼 역산해서 실시간으로 위치를 조정해주면 

    어떨까 생각을 해봤습니다.

     

    일단 검색부터 해봤는데 

     

    stackoverflow.com/questions/54982182/react-beautiful-dnd-drag-out-of-position-problem

     

    React beautiful DnD drag out of position problem

    I created a draggable drag and drop table with draggable rows. I'm using react beautiful-dnd for this. When I drag a row, the row gets out of position instead on the position of my cursor. When I d...

    stackoverflow.com

     

    github.com/atlassian/react-beautiful-dnd/issues/1003

     

    Draggable item offset from mouse cursor due to container CSS. · Issue #1003 · atlassian/react-beautiful-dnd

    Bug or feature request? Help wanted, possible bug Expected behavior The draggable item is under the mouse cursor. Actual behavior The dragable item is offset from the mouse cursor. Steps to reprodu...

    github.com

    저랑 매우 비슷하신 분 이있더라고요

     

    item에 fixed를 먹이라든가, portal을 이용하라는 이야기도 있구 제 생각과 비슷하게

     

    react-spring 모듈을 사용해서 해결하란 분도 계시더라구요

     

    그래도 portal이 의견이 가장 많길래 그냥 portal로 하기로 마음 먹었습니다 .

     

    일단 해당 컴포넌트 바깥에 div를 하나 만들어줬습니다.

     

    이 div 기준으로 컴포넌트가 렌더링 될거에요 

     

     

    그리고 드래깅되는 실시간 검색어 item에 포탈을 사용하게 끔 만들었습니다

    class PortalAwareItem extends Component<ItemProps> {
      render() {
        const provided: DraggableProvided = this.props.provided;
        const snapshot: DraggableStateSnapshot = this.props.snapshot;
        const terms: Terms = this.props.terms;
        const isDragging = this.props.isDragging;
        const isGroupedOver = this.props.isGroupedOver;
        const usePortal: boolean = snapshot.isDragging;
        const child = (
          <Fragment>
            <TermsItem
              key={terms.keyword}
              terms={terms}
              isDragging={isDragging}
              isGroupedOver={isGroupedOver}
              provided={provided}
            />
          </Fragment>
        );
    
        if (!usePortal) {
          return child;
        }
        let portal;
        if (document) {
          portal = document.getElementById('portal');
        }
        // if dragging - put the item in a portal
        return ReactDOM.createPortal(child, portal);
      }
    }

     

    기존 사용하던 TermsItem을 PortalAwareItem으로 감싸주었는데요 

     

    유심히 볼 부분은 

     

    isDragging 이 true일 때 usePortal 이라는 값을 통해서 

     

    ReactDom.createPortal을 통해 아까전에 만들어놓은 div에서 렌더링 되게 해놓은겁니다. ㅎㅎ

     

    이제 한번 결과물을 볼까요..

     

    짠!

     

    아주 정상동작을 하네요 ㅠㅠ

    주륵..

     

    시간 좀 걸리겠는데 싶었었는데 역시 갓 구글은 저를 또 살려주었습니다

     

    이렇게 리액트 포탈을 사용해보았는데 앞으로는 모달컴포넌트라든가 조금 사용성 있을 부분에

     

    포탈을 거리낌 없이 사용 해볼수 있을것 같습니다.ㅎㅎ

    댓글

Designed by Tistory.