react-dnd not detecting hover and drop events

4.6k views Asked by At

I'm having trouble getting react-dnd to to work. Specifically, while I can confirm dragging is being detected properly, my droppable targets are not detecting hover or drop events. I've been following the example at http://survivejs.com/react/implementing-kanban/drag-and-drop/ to create a draggable item. I've tried to use a combination of the same examples and the official examples from the official repo to create a DropTarget to accept the draggable. However, my DropTarget is giving no indication that it is detecting the draggable. My code below has multiple debugger statements to indicate if code is being reached, but none of them ever are. I suspect that the compose call at the end might be the problem, but I'm following Dan Abramov's example here. Just to add to the problem, the React inspector in Chrome dev tools lets me see the itemType state variable change as I drag an item. However, both the canDrop and isOver state variables remain false. I'd appreciate any help to get this to work.

import { findDOMNode } from 'react-dom';
import React, { Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Paper from 'material-ui/Paper';
import FaDelete from 'react-icons/lib/fa/trash-o';
import RaisedButton from 'material-ui/RaisedButton';
import FaEdit from 'react-icons/lib/fa/star';
import actions from '../actions/actions';
import TextField from 'material-ui/TextField';
import { connect } from 'react-redux';
//import EmojiPickerPopup from './EmojiPickerPopup';
import RenderIf from 'render-if';
import globals from '../globals';
import { DropTarget } from 'react-dnd';
import { compose } from 'redux';

const locationItemContainer = {
    display: 'flex',
    flexDirection: 'column',
    backgroundColor: 'lightgoldenrodyellow',
    border: '1px solid Moccasin',
    width: "33%",
    maxHeight: "15em"
}

const controlsContainer = {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-around',
    width: "100%"
}

const paperStyle = {
    padding: '8px 4px',
    display: 'flex',
    flexDirection: "column",
    alignItems: 'center',
    justifyContent: 'center',
    width: "100%",
    height: "100%"
};

class LocationItemComponent extends Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            locationMarkers: []
        }
    }

    componentWillReceiveProps(nextProps) {
        if (!this.props.isOver && nextProps.isOver) {
            // You can use this as enter handler
            debugger
        }

        if (this.props.isOver && !nextProps.isOver) {
            // You can use this as leave handler
            debugger
        }

        if (this.props.isOverCurrent && !nextProps.isOverCurrent) {
            // You can be more specific and track enter/leave
            // shallowly, not including nested targets
            debugger
        }
    }

    nameChanged = (id, event, value) => {
        this.props.dispatch(actions.storyMapActions.updateMarkerName(value, id));
    }
    deleteMarker = (id) => {
        this.props.dispatch(actions.storyMapActions.deleteMarker(id));
    }
    showEmojiPicker = (id, event) => {
        this.props.dispatch(actions.modalsActions.showEmojiPicker(id, event.currentTarget))
    }
    render() {
        const { isOver, canDrop, connectDropTarget } = this.props;
        if (isOver) {
            console.log("is over");
        }
        return connectDropTarget(
            <div style={locationItemContainer}>
                <MuiThemeProvider>
                    <Paper zDepth={5}
                        style={paperStyle}
                        rounded={false}>
                        <TextField
                            id="markerName"
                            hintText="marker Name"
                            onChange={this.nameChanged.bind(this, this.props.marker.id)}
                            value={this.props.marker.name}
                            underlineFocusStyle={{ color: globals.textUnderlineColor }}
                            />
                        <div style={controlsContainer}>
                            <RaisedButton
                                icon={<FaEdit />}
                                primary={true}
                                onClick={this.showEmojiPicker.bind(this, this.props.marker.id)} />
                            <RaisedButton
                                icon={<FaDelete />}
                                secondary={true}
                                onClick={this.deleteMarker.bind(this, this.props.marker.id)} />
                        </div>
                    </Paper>
                </MuiThemeProvider>
            </div>
        );
    }
}
const mapStateToProps = (state) => {
    return Object.assign({}, { state: state });
}

const locationTarget = {
    canDrop(props, monitor) {
        debugger;
        // You can disallow drop based on props or item
        const item = monitor.getItem();
        return true;
    },

    hover(props, monitor, component) {
        debugger;
        // This is fired very often and lets you perform side effects
        // in response to the hover. You can't handle enter and leave
        // hereā€”if you need them, put monitor.isOver() into collect() so you
        // can just use componentWillReceiveProps() to handle enter/leave.

        // You can access the coordinates if you need them
        const clientOffset = monitor.getClientOffset();
        const componentRect = findDOMNode(component).getBoundingClientRect();

        // You can check whether we're over a nested drop target
        const isJustOverThisOne = monitor.isOver({ shallow: true });

        // You will receive hover() even for items for which canDrop() is false
        const canDrop = monitor.canDrop();
    },

    drop(props, monitor, component) {
        debugger;
        if (monitor.didDrop()) {
            // If you want, you can check whether some nested
            // target already handled drop
            debugger
            return;
        }
        // Obtain the dragged item
        const item = monitor.getItem();

        // You can do something with it
        //ChessActions.movePiece(item.fromPosition, props.position);

        // You can also do nothing and return a drop result,
        // which will be available as monitor.getDropResult()
        // in the drag source's endDrag() method
        return { moved: true };
    }
};

const collect = (connect, monitor) => {
    return {
        connectDropTarget: connect.dropTarget(),
        isOver: monitor.isOver(),
        canDrop: monitor.canDrop(),
        itemType: monitor.getItemType()
    };
}

export default compose(
    connect(mapStateToProps),
    DropTarget(globals.itemTypes.LOCATION_ITEM, locationTarget, collect)

)(LocationItemComponent);
0

There are 0 answers