Introduction to the
Recently, WHEN I studied how to draw topology diagrams with React, I involved HTML5 drag-and-drop API, and learned about React DnD, a drag-and-drop wizard. React DnD provides a set of drag-and-drop apis that simplify the use of the drag-and-drop API. Here’s how to use React DnD:
Important concepts
React Dnd provides several important apis for us to use:
- DragSource
- DropTarget
- DragDropContext && DragDropContextProvider
DragSource
DragSource is a higher-order component. Components wrapped with DragSource higher-order components can be dragged and dropped.
Basic usage:
import { DragSource } from 'react-dnd'
class MyComponent {
/ *... * /
}
export default DragSource(type, spec, collect)(MyComponent)
Copy the code
Parameters:
-
Type: Specifies the type of the drag element. The value can be string, symbol, or func. Only elements of the same type can be responded to by the drop target.
-
Spec: A JS object that defines methods to describe how drag source responds to drag events.
- BeginDrag (props, monitor, Component): Mandatory. This method is called when the drag starts and must return a JS object describing the element being dragged, such as returning a
{ id: props.id }
Through themonitor.getItem()
Method to get the return result. - EndDrag (props, monitor, Component): Optional. This method is called when the drag stops, passing through
monitor.didDrop()
Can be judgeddrag source
Have you beendrop target
The processing is complete. If thedrop target
的drop
Method returns an object that can be passedmonitor.getDropResult()
Get the return result. - CanDrag (props, monitor): This parameter is optional. You can specify whether the current drag-and-drop operation is allowed.
- IsDragging (props, monitor): Optional. The event that is triggered when you drag it. Note that it cannot be called again in this method
monitor.isDragging()
.
Description of parameters in the method:
- Props: of the current component
props
Parameters. - Monitor: a
DragSourceMonitor
Instance. It allows you to get current drag information, such as the currently being dragged item and its type, current and initial coordinates and offsets, and whether it has been deleted. - Component: is an instance of a component. You can use it to access DOM elements to make position or size measurements, or to call methods defined in the component, or to perform
setState
Operation. Sometimes this may not be obtained in the isDragging, canDrag methodscomponent
This parameter because the instance may not be available when they are called.
- BeginDrag (props, monitor, Component): Mandatory. This method is called when the drag starts and must return a JS object describing the element being dragged, such as returning a
-
Collect: This parameter is mandatory. It infuses the information required during the drag and drop into props of the component and receives connect and monitor parameters.
- connect:
DragSourceConnector
Examples includedragPreview()
和dragSource()
Two methods, the most common ones aredragSource()
This method.- DragSource: Returns a function that is passed to the component to be used to
source DOM
和React DnD Backend
Connect. - DragPreview: Returns a function passed to the component to preview as it drags
DOM
Nodes andReact DnD Backend
Connect.
- DragSource: Returns a function that is passed to the component to be used to
- monitor:
DragSourceMonitor
Examples, including the specific method can refer tohere.
- connect:
DropTarget
DropTarget is a high-level component that can hold a drop component and respond to hover or dropped events.
Basic usage:
import { DropTarget } from 'react-dnd'
class MyComponent {
/ *... * /
}
export default DropTarget(types, spec, collect)(MyComponent)
Copy the code
Parameters:
-
Types: Specifies the drag element type. The value type can be String, symbol, or array. Drop target only accepts drag sources of the same type.
-
Spec: A JS object that defines methods describing how drag targets react to drag events.
- Drop (props, monitor, Component): This parameter is optional. Called when item is placed on the target element. If this method returns a JS object, the
drag source
的endDrag
Method, callmonitor.getDropResult()
You can get the return result. - Hover (props, monitor, Component): Optional parameter. When the item after
drop target
Is called when. Can be achieved bymonitor.isOver({ shallow: true })
Method to check whether the hover occurs only on the current target or nested. - CanDrop (props, monitor): This parameter is optional. This method can be used for detection
drop target
Whether to accept item.
Description of parameters in the method:
- Props: of the current component
props
Parameters. - Monitor: a
DropTargetMonitor
Instance. It allows you to get current drag information, such as the currently being dragged item and its type, current and initial coordinates and offsets, and whether it has been deleted. - Component: is an instance of a component. You can use it to access DOM elements to make position or size measurements, or to call methods defined in the component, or to perform
setState
Operation. Sometimes this may not be obtained in the isDragging, canDrag methodscomponent
This parameter because the instance may not be available when they are called.
- Drop (props, monitor, Component): This parameter is optional. Called when item is placed on the target element. If this method returns a JS object, the
-
Collect: This parameter is mandatory. It infuses the information required during the drag and drop into props of the component and receives connect and monitor parameters.
- connect:
DropTargetConnector
Examples includedropTarget
One way.- DropTarget: Returns a function passed to the component that will
source DOM
和React DnD Backend
Connect.
- DropTarget: Returns a function passed to the component that will
- monitor:
DropTargetMonitor
Examples, including the specific method can refer tohere.
- connect:
DragDropContext && DragDropContextProvider
Components wrapped with DragSource and DropTarget must be placed inside the DragDropContext or DragDropContextProvider component.
Basic usage:
import Backend from 'react-dnd-html5-backend'
import { DndProvider } from 'react-dnd'
export default function MyReactApp() {
return (
<DndProvider backend={Backend}>
/* your drag-and-drop application */
</DndProvider>)}Copy the code
Parameters:
- Backend: Mandatory. HTML5 DnD API is not compatible and is not suitable for mobile terminals. Therefore, IT is better to separate DOM events related to DnD and use Backend as a separate layer, namely Backend. We can define our own Backend according to the conventions provided by React DnD.
The sample
Now that you know the basics of the API, let’s implement the first demo.
Create-react-app: create-react-app: create-react-app: create-react-app: create-react-app
$ create-react-app react-dnd-demo
Copy the code
src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import Container from './Container'
import { DndProvider } from 'react-dnd'
import Backend from 'react-dnd-html5-backend'
function App() {
return (
<div className="App">
<DndProvider backend={Backend}>
<Container />
</DndProvider>
</div>)}const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
Copy the code
src/Container.js
import React from 'react';
import { DropTarget } from 'react-dnd';
import DraggableBox from './DraggableBox';
import Types from './types'
const styles = {
width: '500px'.height: '300px'.position: 'relative'.border: '1px solid black',
}
@DropTarget(
Types.Box,
{
drop: (props, monitor, component) = > {
if(! component) {return;
}
const delta = monitor.getDifferenceFromInitialOffset();
const item = monitor.getItem();
const left = Math.round(delta.x + item.left);
const top = Math.round(delta.y + item.top);
component.moveBox(item.id, left, top);
},
},
(connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
})
)
class Container extends React.Component {
state = {
boxes: {
a: { top: 20.left: 80.title: 'Drag me around' },
b: { top: 180.left: 20.title: 'Drag me too' },
},
}
moveBox = (id, left, top) = > {
const { boxes } = this.state;
this.setState({
boxes: {... boxes, [id]: { ... boxes[id], left, top } } }) } render() {const { isOver, canDrop, connectDropTarget} = this.props;
const { boxes } = this.state;
const isActive = isOver && canDrop;
let backgroundColor = '#ccc';
// When the component is in the Drag Target area, the background color of the current component changes to darkgreen
if (isActive) {
backgroundColor = '# 453467';
}
console.log('qqqq'.this.state.boxes)
return connectDropTarget && connectDropTarget(
<div style={{ . styles.backgroundColor}} >
{Object.keys(boxes).map(item => <DraggableBox {. boxes[item]} id={item} />)}
</div>
)
}
}
export default Container;
Copy the code
As you can see, in the drop method, through the monitor. The getDifferenceFromInitialOffset () method to calculate the every time drop, before the current element and drag-and-drop elements position offset, The monitor. GetItem () method gets which element is currently being dragged (which must be returned in the beginDrag method of the Drag Source), calls the moveBox method on the Component to reset the latest position after the drag. To move the elements.
IsOver () and monitor.candrop () are used to pass isOver and canDrop parameters to the props of the component to determine whether the current component is in the drag state. This can be used to set the container’s background color when it is dragged.
One detail to note here is that the position attribute of the Container is set to relative, so that the elements being dragged are positioned relative to the Container.
src/DraggableBox.js
import React from 'react';
import { DragSource } from 'react-dnd';
import Box from './Box';
import Types from './types'
@DragSource(
Types.Box,
{
beginDrag: (props) = > {
const { id, title, left, top } = props
return { id, title, left, top }
}
},
(connect, monitor)=> ({
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
})
)
class DraggableBox extends React.Component {
getStyle = (a)= > {
const { left, top } = this.props;
const transform = `translate(${left}px, ${top}px)`
return {
position: 'absolute',
transform,
}
}
render() {
const { connectDragSource } = this.props;
return connectDragSource(
<div style={this.getStyle()}><Box {. this.props} / ></div>
)
}
}
export default DraggableBox;
Copy the code
The beginDrag method must return an object that was previously retrieved from the drop method for the currently being dragged component. The positon property must be set to Absolute to facilitate positioning relative to the container. Element movement is controlled by the TRANSFORM property of the CSS.
src/Box.js
import React from 'react';
const styles = {
border: '1px dashed gray'.backgroundColor: 'white'.padding: '0.5 rem 1 rem'.marginRight: '1.5 rem'.marginBottom: '1.5 rem'.cursor: 'move'.display: 'inline-block'
}
class Box extends React.Component {
render() {
const { title, left, right } = this.props;
return (
<div style={{... styles}}>
{title}
</div>)}}export default Box;
Copy the code
conclusion
React DnD: React DnD: React DnD: React DnD: React DnD