드래드 앤 드랍과 관련하여 리액트에서 다음과 같은 두개의 이벤트를 활용해보고자 한다.
- onDrop : 드래그가 끝난 후, 객체를 놓는 장소에 이벤트 발생
- omDragOver : 드래그 시 마우스가 객체 위에 있는 경우 이벤트 발생
두개의 이벤트에 대한 설명은 다음 링크를 참조바란다.
onDragOver 이벤트 관련
onDrop 이벤트 관련
위 두가지를 함께 사용해보려고 한다.
먼저 onDragOver 이벤트는 다음과 같이 작성할 수 있다.
const onDragOver = (event: React.DragEvent) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
};
드래그가 가능하려면 해당 태그에 draggable 이 있어야 한다.
다음으로 드래그한 모형을 내려두었을 때에 해당 모형이 node 에 추가하는 이벤트를 만들어보겠다.
onDrop 함수에 작성해주면 된다.
const [nodes, setNodes, onNodesChange] = useNodesState<Node[]>([]);
const { screenToFlowPosition } = useReactFlow();
const onDrop = useCallback(
(event: React.DragEvent) => {
event.preventDefault();
// 추가하게 될 node 작성
const newNode = {
id: `${v1()}`,
type: 'custom',
position: screenToFlowPosition({
x: event.clientX,
y: event.clientY
}),
data: {}
};
// 기존 nodes 에 추가하기
setNodes((nds) => nds.concat(newNode));
},
[screenToFlowPosition,setNodes]
);
id의 경우, 중복되지 않기 위해서 uuid 를 사용하였는데 new Date로 현재 시간을 id 로 생성하여도 겹치지 않을 것 같다 😅
setNodes가 ReactFlowExample에 있기 때문에 해당 이벤트들을 ReactFlowExample에서 만든 후, ReactFlowCanvas에 내려주었다.
import { useNodesState, useEdgesState, useReactFlow } from "reactflow";
import { v1 } from "uuid";
import "reactflow/dist/style.css";
import EditorTools from "./EditorTools";
import ReactFlowCanvas from "./ReactFlowCanvas";
import { useCallback } from "react";
const ReactFlowExample = () => {
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const { screenToFlowPosition } = useReactFlow();
const onDragOver = (event: React.DragEvent) => {
event.preventDefault();
event.dataTransfer.dropEffect = "move";
};
const onDrop = useCallback(
(event: React.DragEvent) => {
event.preventDefault();
const newNode = {
id: `${v1()}`,
type: "custom",
position: screenToFlowPosition({
x: event.clientX,
y: event.clientY,
}),
data: {},
};
setNodes((nds) => nds.concat(newNode));
},
[screenToFlowPosition, setNodes]
);
return (
<div style={{ width: "100vw", height: "100vh" }}>
<EditorTools />
<ReactFlowCanvas
nodesState={{
nodes,
setNodes,
onNodesChange,
}}
edgesState={{
edges,
setEdges,
onEdgesChange,
}}
onDrop={onDrop}
onDragOver={onDragOver}
/>
</div>
);
};
export default ReactFlowExample;
import ReactFlow, {
Background,
Controls,
MiniMap,
Node,
Edge,
Connection,
addEdge,
} from "reactflow";
import styled from "styled-components";
import CustomNode from "./CustomNode";
import { useCallback } from "react";
const NodeTypes = {
custom: CustomNode,
};
interface IProps {
nodesState: {
nodes: Node<Node[], string | undefined>[];
setNodes: React.Dispatch<
React.SetStateAction<Node<Node[], string | undefined>[]>
>;
onNodesChange: unknown;
};
edgesState: {
edges: Edge<Edge[]>[];
setEdges: React.Dispatch<React.SetStateAction<Edge<Edge[]>[]>>;
onEdgesChange: unknown;
};
onDrop: (event: React.DragEvent) => void;
onDragOver: (event: React.DragEvent) => void;
}
const ReactFlowCanvas = ({
nodesState,
edgesState,
onDrop,
onDragOver,
}: IProps) => {
const { nodes, onNodesChange } = nodesState;
const { edges, setEdges, onEdgesChange } = edgesState;
const onConnect = useCallback(
(params: Edge | Connection) => setEdges((eds) => addEdge(params, eds)),
[setEdges]
);
return (
<ReactFlowStyled
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
nodeTypes={NodeTypes}
onDragOver={onDragOver}
onDrop={onDrop}
>
<Controls />
<MiniMap />
<Background gap={12} size={1} />
</ReactFlowStyled>
);
};
export default ReactFlowCanvas;
const ReactFlowStyled = styled(ReactFlow)`
.react-flow__node-custom {
width: 120px;
height: 120px;
background: conic-gradient(
from -160deg at 50% 50%,
#e92a67 0deg,
#a853ba 120deg,
#2a8af6 240deg,
#e92a67 360deg
);
border-radius: 100%;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
`;
위 영상을 보면 끌어내렸을 때 앞서 만들었던 custom node가 나타나는것들 알 수 있다!
setNode를 할때에 type을 "custom"으로 등록했기 때문이다.
다음 포스팅에서는 editTools 에 잡아둔 도형의 형태로 custom 된 노드들을 등록하여 해당 노드가 드래그앤드랍되었을 때에 올바른 타입으로 등록 될 수 있도록 작업해보고자 한다! 🙇🏻♀️