This article explains the REact-DND API and its usage in detail, and attached a Demo for reference, hoping to provide some help to friends in need.
A concept,
React DnD is a group of React high-level components. When using React DnD, you only need to use the corresponding API to wrap the target component to realize the function of dragging or accepting drag elements. Convert the drag event to the state of the object. You don’t need to determine the state of the drag. You just need to handle the state properties in the passed spec object. It may be difficult to understand at first, but it will be very convenient when you are really familiar with the usage.
This article Demo address: React-ndD-dustbin. If it helps, please welcome Star.
2. DragSource: Enables components to be dragged
Wrap the component around a DragSource so it can be dragged.
use
import React, { Component } from 'react';
import { DragSource } from 'react-dnd';
const spec = {
beginDrag(props, monitor, component) {
// Return the property of the object to be selected by itself
return { id: props.id } } endDrag(props, monitor, component) { ... } canDrag(props, monitor) { ... } isDragging(props, monitor) { ... }}const collect = (connect, monitor) = > ({
// Returns an object and assigns its properties to the component's props. These attributes need to be defined.
connectDropTarget: connect.dropTarget(),
id: monitor.getItem().id
})
@DragSource(type, spec, collect)
class MyComponent extends Component {
/ *... * /
}
export default MyComponent;
Copy the code
Explanation of parameters:
- Type: required. String, ES6 symbol, or functions that return the given component. Only those registered for the same type
drop targets
Will react to the dragging source generated item - Spec: Required. A normal JavaScript object with some allowed methods. It describes how the drag source responds to drag-and-drop events.
- Collect: Mandatory. Collection function. It should return a normal object to inject into your component. It receives two parameters: connect and monitor.
- Options: Optional. A normal object.
Method in a spec object
-
BeginDrag (props, monitor, Component) : Mandatory. BeginDrag is called when the drag starts. You must return a pure JavaScript object that describes the data being dragged. The content you return is placed in the object obtained by monitor.getitem ().
-
EndDrag (props, monitor, component) : optional. EndDrag is called when the drag stops. For each beginDrag, endDrag will correspond.
-
CanDrag (props, monitor) : This is optional. Use it to specify whether dragging is currently allowed. If you want to always allow it, simply omit this method. Note: You may not be able to call this method monitor.candrag ().
-
IsDragging (props, monitor) : optional. By default, only a drag source that starts a drag operation is considered a drag. Note: You may not be able to call the monitor.isdragging () method.
Methods props, monitor, and component
props
: of the current componentprops
monitor
A:DragSourceMonitor
Instance. Use it to query information about the current drag state, such as the item being dragged and its type, current and initial coordinates and offsets, and whether it has been deleted.component
: When specified, it is an instance of the component. Use it to access the underlying DOM node for position or size measurements, or to invokesetState
And other component methods.isDragging
,canDrag
Methodcomponent
Because the instance may not be available when they are called
Connect and monitor parameters in collect
-
Connect: a DragSourceConnector instance. It comes in two ways: dragPreview() and dragSource().
- dragSource() => (elementOrNode, options?) A common method that returns a function passed to the component to connect Source DOM to React DnD Backend
- DragPreview () : Returns a function passed to the component to connect React DnD Backend to the DOM node it previews while dragging
- dragSource() => (elementOrNode, options?) A common method that returns a function passed to the component to connect Source DOM to React DnD Backend
-
Monitor: a DragSourceMonitor instance. This includes the following methods:
methods | meaning |
---|---|
canDrag() |
Whether it can be dragged. Returns true if no drag operation is in progress |
isDragging() |
Whether it is being dragged. Returns true if a drag operation is in progress |
getItemType() |
Returns a string or ES6 symbol that identifies the type of the currently dragged item. Returns if the item is not draggednull |
getItem() |
Returns a normal object representing the currently dragged item. Each drag source must specify it by returning an object from its beginDrag () method. Returns if the item is not draggednull |
getDropResult() |
Returns the placement representing the last recorddrop result object |
didDrop() |
If adrop target Deal with thedrop Event, return true, otherwise return false. Even if thetarget There is no returndrop As a result,didDrop() It also returns true. inendDrag() Is used to test whether any placed target has handled the drop. If theendDrag() If not called, returns false |
getInitialClientOffset() |
Returns {x, y} from the pointer at the start of the current drag operationclient The offset. Returns if the item is not draggednull |
getInitialSourceClientOffset() |
Returns to the beginning of the current drag operationdrag source {x, y} for the component’s root DOM nodeclient The offset. Returns if the item is not draggednull |
getClientOffset() |
Return the last record of the pointer {x, y} while the drag operation is in progressclient The offset. Returns if the item is not draggednull |
getDifferenceFromInitialOffset() |
Returns the last record of the mouse at the beginning of the current drag operationclient The offset andclient The {x, y} difference between offsets. Returns if the item is not draggednull |
getSourceClientOffset() |
returndrag source Expected {x, y} for the component’s root DOM nodeclient Offset based on its position at the start of the current drag operation and the movement difference. Returns if the item is not draggednull |
DropTarget: Enables components to drop drag components
Wrap a component around a DropTarget to react to a drag, hover, or dropped compatible item.
use
import React, { Component } from 'react';
import { DropTarget } from 'react-dnd';
const spec = {
drop(props, monitor, component) {
// Return the property of the object to be selected by itself
return { id: props.id } } hover(props, monitor, component) { ... } canDrop(props, monitor) { ... }}const collect = (connect, monitor) = > ({
// Returns an object and assigns its properties to the component's props. These attributes need to be defined.
connectDropTarget: connect.dropTarget()
})
@DropTarget(type, spec, collect)
class MyComponent extends Component {
/ *... * /
}
export default MyComponent;
Copy the code
Explanation of parameters:
- Type: required. String, ES6 symbol, or functions that return the given component. This place target is only for the specified type
drag sources
Project response - Spec: Required. A normal JavaScript object with some allowed methods. It describes how the drop target responds to the drag and drop event.
- Collect: Mandatory. Collection function. It should return a normal item object to inject into your component. It receives two parameters: connect and monitor.
- Options: Optional. A normal object.
Method in a spec object
-
Drop (props, monitor, component) : This is optional. Called when a compatible item is placed on the target. You can return undefined or a normal object. If an object is returned, it will be the result of the placement, which can be obtained using monitor.getDropresult ().
-
Hover (props, monitor, component) : optional. Called when the project hovers over the component. You can check monitor.isover ({shallow: true}) to test whether the hover occurs only on the current target or nested.
-
CanDrop (props, monitor) : This is optional. Use it to specify whether the project can be accepted by the place target. If you want to always allow it, simply omit this method.
The document does not provide a way to process the entry or exit events for their purpose. Instead, monitor.isover () returns the result of the call from the collection function so that we can use the componentDidUpdateReact hook function to handle the entry and exit events in the component.
Methods props, monitor, and component
props
: of the current componentprops
monitor
A:DropTargetMonitor
Instance. Use it to query information about the current drag state, such as the item being dragged and its type, current and initial coordinates and offsets, whether the current target is exceeded, and whether it can be deleted.component
: When specified, it is an instance of the component. Use it to access the underlying DOM node for position or size measurements, or to invokesetState
And other component methods.canDrag
Methodcomponent
Because the instance may not be available when they are called.
Connect and monitor parameters in collect
-
Connect: a DropTargetConnector instance. It has only one dropTarget() method.
dropTarget() => (elementOrNode)
A common method that returns a function passed to the component to connect target DOM to React DnD Backend. Any React element can be marked as a placeable node by {connectDropTarget: connect.dropTarget()} returned from the collection function.
-
Monitor: A DropTargetMonitor instance. This includes the following methods:
methods | meaning |
---|---|
canDrop() |
Whether it can be placed. Returns true if a drag operation is in progress |
isOver(options) |
drag source Whether to hover overdrop target Area. You can choose to pass{ shallow: true } To strictly check if onlydrag source Hover instead of nesting targets |
getItemType() |
Returns a string or ES6 symbol that identifies the type of the currently dragged item. Returns if the item is not draggednull |
getItem() |
Returns a normal object representing the current drag item, which each drag source must specify by returning an object from its beginDrag() method. Returns if the item is not draggednull |
getDropResult() |
Returns the placement representing the last recorddrop result object |
didDrop() |
If adrop target Deal with thedrop Event, return true, otherwise return false. Even if thetarget There is no returndrop As a result,didDrop() It also returns true. inendDrag() Is used to test whether any placed target has handled the drop. If theendDrag() If not called, returns false |
getInitialClientOffset() |
Returns {x, y} from the pointer at the start of the current drag operationclient The offset. Returns if the item is not draggednull |
getInitialSourceClientOffset() |
Returns to the beginning of the current drag operationdrag source {x, y} for the component’s root DOM nodeclient The offset. Returns if the item is not draggednull |
getClientOffset() |
Return the last record of the pointer {x, y} while the drag operation is in progressclient The offset. Returns if the item is not draggednull |
getDifferenceFromInitialOffset() |
Returns the last record of the mouse at the beginning of the current drag operationclient The offset andclient The {x, y} difference between offsets. Returns if the item is not draggednull |
getSourceClientOffset() |
returndrag source Expected {x, y} for the component’s root DOM nodeclient Offset based on its position at the start of the current drag operation and the movement difference. Returns if the item is not draggednull |
DragDropContext & DragDropContextProvider
Note: Components that use the DragSource and DropTarget packages must be placed inside either the root component of the: DragDropContext package or the root tag of the DragDropContextProvider.
DragDropContext
Use DragDropContext to wrap the root component of your application to enable React DnD.
usage
import React, { Component } from 'react';
import HTML5Backend from 'react-dnd-html5-backend';
import { DragDropContext } from 'react-dnd';
@DragDropContext(HTML5Backend)
class YourApp extends Component {
/ *... * /
}
export default YourApp;
Copy the code
parameter
-
Backend: Mandatory. A React DnD backend. Unless you are writing a custom one, it is recommended to use HTML5Backend, which comes with React DnD.
-
Context: Backend depends. Context object used to customize the backend. For example, HTML5Backend can inject custom window objects for iframe scenarios.
DragDropContextProvider
As an alternative to DragDropContext, you can use the DragDropContextProvider element to enable React DnD for your application. Similar to DragDropContext, this can be injected into the backend via BackendProp, but a Window object can also be injected.
usage
import React, { Component } from 'react';
import HTML5Backend from 'react-dnd-html5-backend';
import { DragDropContextProvider } from 'react-dnd';
export default class YourApp extends Component {
render() {
return (
<DragDropContextProvider backend={HTML5Backend}>/ *... * /</DragDropContextProvider>)}}Copy the code
parameter
-
Backend: Mandatory. A React DnD backend. Unless you are writing a custom one, it is recommended to use HTML5Backend, which comes with React DnD.
-
Context: Backend depends. Context object used to customize the backend. For example, HTML5Backend can inject custom window objects for iframe scenarios.
A simple example of React-DND
Refer to the official Dustbin example for this example.
Project preparation
The current project is built using create-React-app scaffolding and is written using decorator syntax when using React-Dnd. So you need to add some configuration to your project first.
For the decorator enabled configuration, see my previous article: Enable decorator syntax in create-React-App.
Create a Components folder to hold the components you wrote. Create a types folder to store type string constants, and create an index.js file in the types directory to declare the corresponding type value.
types/index.js
export default {
BOX: 'box'
}
Copy the code
So the current project SRC directory file structure is as follows:
SRC ├── components/ ├── types/ ├─ index.js ├── app.js ├─ index.css ├─ index.jsCopy the code
Create the Box component as the DragSource
In the Components directory, create the box.js file and write the Box component so that it can be dragged
components/Box.js
import React from 'react';
import PropTypes from 'prop-types';
import { DragSource } from 'react-dnd';
import ItemTypes from '.. /types';
const style = {
border: '1px dashed gray'.backgroundColor: 'white'.padding: '0.5 rem 1 rem'.marginRight: '1.5 rem'.marginBottom: '1.5 rem'.cursor: 'move'.float: 'left',}const boxSource = {
@param {*} props */ props */
beginDrag(props) {
// The returned object can be obtained in monitor.getitem ()
return {
name: props.name,
}
},
@param {*} props props for the current component * @param {*} Monitor DragSourceMonitor object */
endDrag(props, monitor) {
// The item component being dragged
const item = monitor.getItem()
// Drop the element, drop the result
const dropResult = monitor.getDropResult()
// If the drop result exists, an alert is displayed
if (dropResult) {
alert(`You dropped ${item.name} into ${dropResult.name}! `)
}
},
}
@DragSource(
// Type id, here is the string 'box'
ItemTypes.BOX,
// Drag the event object
boxSource,
// Collect function functions, including connect and monitor parameters
// Connect connects DOM nodes to React-dnd backend
(connect, monitor) => ({
// Wrap the DOM node so that it can be dragged and dropped
connectDragSource: connect.dragSource(),
// Whether it is in the drag state
isDragging: monitor.isDragging(),
}),
)
class Box extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
isDragging: PropTypes.bool.isRequired,
connectDragSource: PropTypes.func.isRequired
}
render() {
const { isDragging, connectDragSource } = this.props
const { name } = this.props
const opacity = isDragging ? 0.4 : 1
// Wrap the DOM node with connectDragSource so that it can accept various drag apis
// connectDragSource can drag only DOM nodes wrapped by connectDragSource
return connectDragSource && connectDragSource(
<div style={{ . style.opacity}} >
{name}
</div>); }}export default Box;
Copy the code
Create a Dustbin component as a DropTarget
In the Components directory, create a dustbin. js file and write a Dustbin component so that it can accept the corresponding drag-and-drop component.
components/Dustbin.js
import React from 'react';
import PropTypes from 'prop-types';
import { DropTarget } from 'react-dnd';
import ItemTypes from '.. /types';
const style = {
height: '12rem'.width: '12rem'.marginRight: '1.5 rem'.marginBottom: '1.5 rem'.color: 'white'.padding: '1rem'.textAlign: 'center'.fontSize: '1rem'.lineHeight: 'normal'.float: 'left',}const boxTarget = {
// When a corresponding drag source is placed in the current component area, an object is returned, which can be obtained in monitor.getDropresult ()
drop: (a)= > ({ name: 'Dustbin' })
}
@DropTarget(
// Type id, here is the string 'box'
ItemTypes.BOX,
// Receive drag-and-drop event objects
boxTarget,
// Collect function functions, including connect and monitor parameters
// Connect connects DOM nodes to React-dnd backend
(connect, monitor) => ({
// Wrap the DOM node so that it can receive the corresponding drag component
connectDropTarget: connect.dropTarget(),
// Drag whether the source is in the drop Target area
isOver: monitor.isOver(),
// Can be placed
canDrop: monitor.canDrop(),
})
)
class Dustbin extends React.Component {
static propTypes = {
canDrop: PropTypes.bool.isRequired,
isOver: PropTypes.bool.isRequired,
connectDropTarget: PropTypes.func.isRequired
}
render() {
const { canDrop, isOver, connectDropTarget } = this.props;
const isActive = canDrop && isOver;
let backgroundColor = '# 222';
// When the component is in the Drag target area, the background color of the current component changes to darkgreen
if (isActive) {
backgroundColor = 'darkgreen';
}
// When the current component can place the Drag source, the background color changes to pink
else if (canDrop) {
backgroundColor = 'darkkhaki';
}
// Wrap the DOM node with a connectDropTarget so that it can receive the corresponding Drag Source component
// Only DOM nodes wrapped by connectDropTarget can receive drag Source components
return connectDropTarget && connectDropTarget(
<div style={{ . style.backgroundColor}} >
{isActive ? 'Release to drop' : 'Drag a box here'}
</div>); }}export default Dustbin;
Copy the code
Use DragDropContext in the app.js file
App.js
import React, { Component } from 'react';
import { DragDropContext } from 'react-dnd';
import HTMLBackend from 'react-dnd-html5-backend';
import Dustbin from './components/Dustbin';
import Box from './components/Box';
// Pass HTMLBackend as argument to DragDropContext
@DragDropContext(HTMLBackend)
class App extends Component {
render() {
return (
<div style={{ paddingLeft: 200, paddingTop: 50 }}>
<div style={{ overflow: 'hidden', clear: 'both' }}>
<Box name="Glass" />
<Box name="Banana" />
<Box name="Paper" />
</div>
<div style={{ overflow: 'hidden', clear: 'both' }}>
<Dustbin />
</div>
</div>
);
}
}
export default App;
Copy the code
Run the project to see the effect
Running projects:
$ npm run start
Copy the code
The browser will automatically open the http://localhost:3000/ window. At this time, you can operate the Box component on the browser and view the effect combined with the project code. The preview looks like this:
6. Address of Demo
react-dnd-dustbin
Welcome to Star! Thank you very much!
Vii. Reference links
React DND Official document drag component: Use of React DND