드래그 앤 드롭 기능
넘후 어려웠지만 복붙으로 해결
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()
export const ItemTypes = {
CARD: 'card',
}
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 *************************************************/
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>
)