RecoFashion - ReactDnD를 이용해 Drag & Drop 기능 구현하기

백근영·2019년 11월 29일
0
post-thumbnail

프론트 단에서 구현해야 할 핵심 기능 중 하나는 여러 가지 추천 색상을 브라우저에 띄워주고 나면, 이 각각의 색상들을 드래그 해서 오늘 입을 상의 or 하의의 색상에 드랍할 수 있도록 하는 것이었다. 드래그앤 드랍 기능을 구현해본 적이 없어서 처음엔 매우 막막했지만, 역시나 구글은 나에게 필요한 모든 것을 알려주었다. (구글 짱!)

React DnD를 이용해 만들어야 할 컴포넌트는 크게 두 개이다.
1. 색상을 제공할 colorBox 컴포넌트
2. colorBox로부터 색상을 가져와 색상을 입힐 colorBin 컴포넌트

우리는 colorBox 컴포넌트를 drag하여 colorBin 컴포넌트에 drop해야 하므로, 이 두 컴포넌트는 각각 react dnd에서 제공하는 dragSource 함수와 dropTarget 함수로 wrapping하여 export 해준다.

ColorBox.tsx

import React from "react";
import {
  ConnectDragSource,
  DragSource,
  DragSourceConnector,
  DragSourceMonitor
} from "react-dnd";

interface Props {
  color: string;
  isDragging: boolean;
  connectDragSource: ConnectDragSource;
  handleChangeColorBin: (
    color: string,
    type: "topColor" | "pantsColor"
  ) => void;
}

const ColorBox = (props: Props) => {
  const opacity = props.isDragging ? 0.4 : 1;

  return props.connectDragSource(
    <div
      style={{
        backgroundColor: `#${props.color}`,
        width: "40px",
        height: "40px",
        opacity
      }}
    >
      {" "}
    </div>
  );
};

export default DragSource(
  "colorBox",
  {
    beginDrag: (props: Props) => {
      return { color: props.color };
    },
    endDrag(props: Props, monitor: DragSourceMonitor) {
      const item = monitor.getItem();
      const dropResult = monitor.getDropResult();

      if (dropResult && dropResult.type) {
        props.handleChangeColorBin(item.color, dropResult.type);
      }
    }
  },
  (connect: DragSourceConnector, monitor: DragSourceMonitor) => ({
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging()
  })
)(ColorBox);

dragSource함수의 callback function으로 2가지 함수를 작성했다.
1. beginDrag : drag event가 시작될 때 실행할 작업. 내가 드래그 하는 대상에 대한 특정 정보를 return한다.
2. endDrag : drag event가 끝났을 때 실행할 작업. dropTarget으로부터 받아온 dropResult를 가지고 원하는 작업을 수행한다.

나의 경우 beginDrag 함수에서 내가 drag하고 있는 colorBox의 색상 정보를 리턴해주었고, endDrag함수에서 내가 drop한 대상이 상의 colorBin인지 하의 colorBin인지에 대한 정보를 담아 handler함수를 실행시켰다.

ColorBin.tsx

import React from 'react';
import {ConnectDropTarget, DropTarget} from "react-dnd";
import {Color} from './types'
import {switchColorToStr} from './utils'

interface Props {
    color: Color
    type: "topColor" | "pantsColor"
    connectDropTarget: ConnectDropTarget
    canDrop: boolean
    isOver: boolean
}

const ColorBin = (props: Props) => {
    const isActive = props.canDrop && props.isOver
    const phrase = isActive ? "drop here!" : ""

    const style = {
      backgroundColor: `#${switchColorToStr(props.color)}`,
      border: '1px dashed black',
      height: '100px',
      width: '100px'
    }

    return props.connectDropTarget(
        <div style={style}>
            {phrase}
        </div>
    )
};

export default DropTarget(
    'colorBox',
    {
        drop: (props: Props) => ({
            type: props.type
        })
    },
    (connect, monitor) => ({
        connectDropTarget: connect.dropTarget(),
        isOver: monitor.isOver(),
        canDrop: monitor.canDrop(),
    }),
)(ColorBin)

dropTarget에서는 dragSource의 endDrag 함수가 받을 dropResult를 생성해주어야 하는데, 이 colorBin이 상의인지 하의인지에 대한 정보를 담고 있는 type 변수를 실어 리턴해주었다.

구체적인 코드 및 실행 모습은 아래에서 확인할 수 있다.

profile
서울대학교 컴퓨터공학부 github.com/BaekGeunYoung

0개의 댓글