6

Using React Dnd v15.1.1

I need to get the target element on drop either their Id or the whole object

I tried

const [{ canDrop, isOver }, drop] = useDrop(
  () => ({
     accept: ItemType,
     drop: (item, monitor) => addTaskToSprint(item.id, monitor),
  })
);

And here's addTaskToSprint declaration

const addTaskToSprint = (id, monitor) => {
    console.log(monitor.getDropResult());

    let body = {
       sprint: { 
          id: , //here where I need the target Drop Id 
       }
    };
    axios.put(process.env.REACT_APP_API_URL + "/tasks/" + id, body, {
        headers: { Authorization: `Bearer ${jwt}` },
    });
};

monitor.getDropResult() is returning null in the console

Then I tried the same process inside the drag declaration

const [{ isDragging }, drag] = useDrag(() => ({
    type: ItemType,
    item: task,
    collect: (monitor) => ({ isDragging: !!monitor.isDragging() }),
    end(item, monitor) {
        console.log(monitor.getDropResult());
    },
}));

And in here it's returning the dropEffect. Here's the logs

{
   "dropEffect": "move"
}

When I console.log(monitor) inside the drop result it gave me

console results to logging monitor object

Where targetId is the targeted drop element, but this Id is generated by react-dnd not the actual Id of the element

When I open the internalMonitor object from the picture above

I got inside nested objects all the drop Targets with their generated Id from react-dnd but I couldn't get the object of each Id (to get the target drop object)

console result of internalMonitor object

And here's how each object looks like

0: {"T0" => DropTargetImpl}
    key: "T0"
    value: DropTargetImpl
        monitor: DropTargetMonitorImpl
        internalMonitor: DragDropMonitorImpl
        registry: HandlerRegistryImpl {types: Map(8), dragSources: Map(4), dropTargets: Map(4), pinnedSourceId: null, pinnedSource: null, …}
        store: {dispatch: ƒ, subscribe: ƒ, getState: ƒ, replaceReducer: ƒ, @@observable: ƒ}
    spec:
      accept: "Task Card"
      collect: monitor => {…}
      drop: (item, monitor) => addTaskToSprint(item.id, monitor, drop)

To be clearer, check the screenshot of the results in the console

enter image description here

Hiba abdel karim
  • 122
  • 2
  • 10

2 Answers2

1

I have faced the same challenge trying to use the monitor object of react dnd library, but was getting the same result as yours. I decided to share here how I've solved that. The solution is pretty simple and you can pass whatever info you need to the props collection when rendering the draggable / droppable component and then you use that info within the useDrag() / useDrop() methods.

Here below is an example of how to control draggable answers, so that to be dropped on a form depending on the exercise / task they belong to (item.task_id === props.task_id):

function DnDAnswerTarget(props) {
const [{canDrop, isOver}, drop] = useDrop({
    accept: // ItemTypes to be specified,
    canDrop: (item, monitor) => {
        return (item.task_id === props.task_id ? true : false);
    },
    drop: (item, monitor) => {
       // Some code for the ondrop event to be executed...
    },
    collect: (monitor) => (
        {
        canDrop: !!monitor.canDrop(),
        isOver: !!monitor.isOver()
    })
});
return (
    <Box ref={drop}
    >
        {props.children}
    </Box>
  );
}
export default DnDAnswerTarget;
Sonic
  • 11
  • 2
1

Part of the problem here is that monitor.getDropResult() gives you the value returned by your drop() function, but if you're calling addTaskToSprint() directly from drop() then the drop result isn't available yet.

You have a couple of choices here.

If you want to call addTaskToSprint() from the drop target, you might add an extra parameter to accept the target id directly:

drop: (task) => addTaskToSprint(task.id, sprint.id)

Alternatively, if you want to call addTaskToSprint from the dragged object, you could return the target element id from the drop() function and it will be available to the end handler:

// in useDrop() ...
drop: () => ({ sprintId: sprint.id })

// in useDrag() ...
end(task, monitor) {
    const dropResult = monitor.getDropResult();
    addTaskToSprint(task.id, dropResult.sprintId);
}
motto
  • 2,888
  • 2
  • 2
  • 14