The first article of my personal blog: original link

I learned React DnD after reading the code attached to how to Write a Drag calendar component. I couldn’t understand the code related to the drag calendar component React DnD.

This article explains how to use the basic drag and drop usage of React DnD by showing garbage (box.jsx) into Dustbin (dustbin.jsx) in the root component (contaier.jsx).

Preview the trash can effect

View garbage can source code

Core API

To be flexible, you need to know a few core apis

  • DragSource wraps components that you need to drag to make it draggable
  • DropTarget is used to wrap a component that receives drop elements so that the component can be dropped on it.
  • DragDropContexUsed to wrap the drag root component,DragSourceDropTargetThey all need to be wrappedDragDropContexWithin the
  • DragDropContextProviderDragDropContexA similar,DragDropContextProviderElement wrap drag root component.

With a general understanding of these API concepts, the code for garbage (box.jsx) into Dustbin (dustbin.jsx) will look like this:

// Box.jsx
import { DragSource } from 'react-dnd';

@DragSource(type, spec, collect)
export default class Box {
  / *... * /
}

// Dustbin.jsx
import { DropTarget } from 'react-dnd';

@DropTarget(types, spec, collect)
export default class Contaier {
  / *... * /
}

// Contaier.jsx (DragDropContex)
import { DragDropContext } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import Box from './Box';
import Dustbin from './Dustbin';

@DragDropContext(HTML5Backend)
export default class Contaier extends Component {
  render() {
    return (
      <div>
          <Dustbin/>
          <Box/>
      </div>); }}// Contaier.jsx (DragDropContextProvider)
import { DragDropContextProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import Box from './Box';
import Dustbin from './Dustbin';

export default class DustbinContaier extends Component {
  render() {
    return (
      <DragDropContextProvider backend = { HTML5Backend} >
        <div>
            <Dustbin/>
            <Box/>
        </div>
      </DragDropContextProvider>); }}Copy the code

API Parameters

The code above

@DragSource(type, spec, collect)
@DropTarget(types, spec, collect)
Copy the code

You can see that DragSource and DropTarget have three parameters respectively:

  • Type: indicates the drag type. This parameter is mandatory
  • Spec: method object for the drag event, mandatory.
  • Collect: Inject the information required during the drag process into the props of the component, and receive two parametersconnect and monitorWill fill.

The source component is the dragSource-wrapped component (box.jsx in this example) and the target component is the DropTarget-wrapped component (dustbin.jsx in this example).

type

The target component can accept the Source component when its type is the same as the target component’s type.

Type can be string, symbol, or a function to return other props for the component.

Translated into code:

// itemtypes.js defines the type
export default {
  BOX: 'box',}// Box.jsx
import ItemTypes from './ItemTypes'
@DragSource(ItemTypes.BOX, spec, collect)

// Dustbin.jsx
import ItemTypes from './ItemTypes'
@DropTarget(ItemTypes.BOX, spec, collect)
Copy the code

spec

The spec of the source component can define the drag related event, and the spec of the target component can define the drop related event.

DragSource specObj

  • BeginDrag (props, monitor, Component): The event triggered when the drag starts, must. Returns the object associated with props.

  • EndDrag (props, monitor, Component): Optional event triggered when dragging ends.

  • CanDrag (props, monitor): Optional event that can be dragged or not.

  • IsDragging (props, monitor): Optional event triggered when dragging.

Translated into code:

  // Box.jsx
  const sourceSpec = {
    beginDrag(props, monitor, component){
      // Returns the attributes to be injected
      return {
        id: props.id
      }
    },
    endDrag(props, monitor, component){
      // ..
    },
    canDrag(props, monitor){
      // ..
    },
    isDragging(props, monitor){
      // ..
    }
  }
  @DragSource(ItemTypes.BOX, sourceSpec, collect)
Copy the code

DropTarget specObj

  • drop(props, monitor, component)An optional event that is triggered when the component is dropped.
  • hover(props, monitor, component)The event that the component responds to when above the DropTarget, optional.
  • canDrop(props, monitor)Optional events that trigger when a component can be placed.

Translated into code:

// Dustbin.jsx
const targetSpec = {
  drop(props, monitor, component){
    // ..
  },
  hover(props, monitor, component){
    // ..
  },
  canDrop(props, monitor){
    // ..
  }
}
@DropTarget(ItemTypes.BOX, targetSpec, collect)
Copy the code

SpecObj object method parameters

  • Props: current props of the component
  • Monitor: Queries the current drop status, such as the drop item and its type, the drop offsets, and whether the drop is enabled. For details on how to obtain it, seeCollect Parameter Monitor part
    • The source componentThe monitor parameter ofDragSourceMonitorAn instance of the
    • The target componentThe monitor parameter ofDropTargetMonitorAn instance of the
  • Component: Current component instance

collect

Collect is a function that takes two parameters by default: connect and monitor. The collect function returns an object that is injected into the props of the component, that is, we can get all the properties returned by Collect via this.props.

Parameters of the connect

  • The source componentConnect is collectDragSourceConnectorClass, which has two built-in methods:dragSource()dragPreview().dragSource()Returns a method that willThe source componentUsing this method, you can connect the Source DOM to React DnD Backend.dragPreview()Returns a method that you can pass in as a node to play a role in drag preview.
  • The target componentConnect is collectDropTargetConnectorInstance of the built-in methoddropTarget()The correspondingdragSource(), returns a method that can connect drop target to React DnD Backend.

Translated into code:

// Box.jsx
@DragSource(ItemTypes.BOX, sourceSpec,(connect)=>({
  connectDragSource: connect.dragSource(),
  connectDragPreview: connect.dragPreview(),
}))
export default class Box {
  render() {
    const { connectDragSource } = this.props
    return connectDragSource(
      <div>{/ *... * /}</div>)}},// Dustbin.jsx
@DropTarget(ItemTypes.BOX, targetSpec, (connect)=>{
  connectDropTarget: connect.dropTarget(),
})
export default class Dustbin {
  render() {
    const { connectDropTarget } = this.props
    return connectDropTarget(
      <div>{/ *... * /}</div>)}},Copy the code

Parameters of the monitor

Monitor is used to query the current drag-and-drop state, and its instances have many methods built in.

  • The source componentThe monitor is in collectDragSourceMonitorThe instance.
  • The target componentThe monitor is in collectDropTargetMonitorThe instance.

List of built-in methods:

// DragSourceMonitor
monitor.canDrag()        // Whether it can be dragged
monitor.isDragging()      // Whether you are dragging
monitor.getItemType()     // Drag and drop component type
monitor.getItem()         // The currently dragged item
monitor.getDropResult()   // Query the drop result
monitor.didDrop()         // Whether the source has been dropped at target
monitor.getInitialClientOffset()   // The component is initially dragged at offset
monitor.getInitialSourceClientOffset()
monitor.getClientOffset() // Drag the current offset of the component
monitor.getDifferenceFromInitialOffset() // The difference between the current offset drag and the initial offset drag
monitor.getSourceClientOffset()

// DropTargetMonitor
monitor.canDrop()         // Can be placed
monitor.isOver(options)   // Whether source is above target
monitor.getItemType()     // Drag and drop component type
monitor.getItem()         // The currently dragged item
monitor.getDropResult()   // Query the drop result
monitor.didDrop()         // Whether the source has been dropped at target
monitor.getInitialClientOffset()   // The component is initially dragged at offset
monitor.getInitialSourceClientOffset()
monitor.getClientOffset() // Drag the current offset of the component
monitor.getDifferenceFromInitialOffset() // The difference between the current offset drag and the initial offset drag
monitor.getSourceClientOffset()
Copy the code

Concrete example

First drop the official example and source code:

  • The official example
  • Official source code