[react-dnd] 드래그 앤 드롭

DONNIE·2023년 3월 28일
0

React

목록 보기
13/26
post-thumbnail

드래그 앤 드롭 기능
넘후 어려웠지만 복붙으로 해결

  • index.js
    App.js 에서 감싸도 되지만 나는 App.js 에서 component를 import 하지않고 라우터로 연결하기 때문에 index.js 에서 감싸줌
import 'react-app-polyfill/stable'
import 'core-js'
import React from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
import reportWebVitals from './reportWebVitals'
import { Provider } from 'react-redux'
import store from './store'
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend'

createRoot(document.getElementById('root')).render(
  <DndProvider backend={HTML5Backend}>
    <Provider store={store} style={{backgroundColor:"#ffffff"}}>
      <App />
    </Provider>
  </DndProvider>
  ,
)

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals()
  • dnd.js
export const ItemTypes = {
    CARD: 'card',
}
  • DragDrop.js

import React, {useRef} from "react";
import { ItemTypes } from "src/dnd";
import { useDrag, useDrop } from "react-dnd";
import { CButton } from "@coreui/react";
import styled from "styled-components";

const Wrapper = styled.div`
    opacity : ${props => props.isDragging ? 0 : 1}
`
/**
 * 
 * @param {id} 리스트의 id 
 * @param {title} 텍스트 
 * @param {index} 인덱스값 
 * @param {moveList} 변경된 리스트 담는 배열 
 * @param {isDrop} drop 된 상태를 boolean 값으로 받는 state의 setState, ex) setIsDrop
 * @returns 
 */
const DragDrop = ({id,title,index,moveList, isDrop}) =>{

    const ref = useRef(null);

    const [, drop] = useDrop({ // (*)
        accept: ItemTypes.CARD,
        hover(item, monitor) {
          if (!ref.current) {
            return;
          }
    
          const dragIndex = item.index;
          const hoverIndex = index;
    
          if (dragIndex === hoverIndex) {
            return;
          }
    
          const hoverBoundingRect = ref.current?.getBoundingClientRect();
          const hoverMiddleY =
            (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
          const clientOffset = monitor.getClientOffset();
          const hoverClientY = clientOffset.y - hoverBoundingRect.top;
    
          if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
            return;
          }
    
          if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
            return;
          }
    
          moveList(dragIndex, hoverIndex);
          item.index = hoverIndex;
        },
        drop : (item, monitor) =>{
            const didDrop = monitor.didDrop();
            if(!didDrop) {
                isDrop(true) // drop 시 반환하는 boolean 값, true일시 처리할 로직 붙이고 완료후 setIsDrop(false) 해주어야 재사용가능
            }
        }
      });
    
      const [{ isDragging }, drag] = useDrag({ // (*)
        type: ItemTypes.CARD,
        item: { id, index },
        collect: monitor => ({
          isDragging: monitor.isDragging(),
        }),
      });
    
      drag(drop(ref)); // (*)
    
      return (
        <Wrapper ref={ref} isDragging={isDragging}>
          <CButton color="secondary" style={{width:'100%'}}>{title}</CButton>
         </Wrapper>
      );
    };
    
    export default DragDrop;
    
  • ListManage.js

    
    /** 상단 import*/
    import DragDrop from 'src/components/common/DragDrop';
    import update from 'immutability-helper';
    .
    .
    .
    
     /**** 드래그 앤 드롭 테스트 START ***********************************************/
    
    const [isDrop, setIsDrop] = useState(false)
    const [modalTypeList, setModalTypeList] = useState([])
    const moveList = useCallback(
      (dragIndex, hoverIndex)=>{
        const dragList = modalTypeList[dragIndex];
    
        setModalTypeList(
          update(modalTypeList, {
            $splice: [
              [dragIndex, 1],            // delete
              [hoverIndex, 0, dragList], // add
            ]
          })
        )
      },
      [modalTypeList]
    )
    
    useEffect(()=>{
      setModalTypeList(typeList)
    },[typeList])
    
    // drop 시 true 반환, API 통신후 setIsDrop(false)로 바꿔서 처리해야 추후 변경시에도 적용
    useEffect(()=>{
      if(isDrop) {
        console.log('API 보내는 타이밍',modalTypeList) 
      }
    },[isDrop])
    
    /**** 드래그 앤 드롭 테스트 END *************************************************/
  • ListManage.js
return (
 <div className="d-grid gap-2">
          {
            modalTypeList?.map((tl,idx)=>{
            return (
            <DragDrop 
             index={idx}
             id={tl.ciSeq}
             title={tl.ciName}
             moveList={moveList}
             isDrop={setIsDrop}
             key={generateRandomString(9+idx)}
            />
            )
          })
     
</div>
)
profile
후론트엔드 개발자

0개의 댓글