Recur
Recur

Reputation: 1428

react-dnd uncaught typerrors. Trying to follow the simple sortable example

I've been trying to work off of the simple sortable example in the react-dnd examples but I am having trouble trying to convert the es7 code to es6. I've tried using babel but I don't really understand the code that it spits out. Here is my code that I've tried to translate from es7 to es6:

import React, {PropTypes} from 'react';
import Router from 'react-router';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { DragSource, DropTarget } from 'react-dnd';

const style= {
  border: '1px dashed gray',
  padding: '0.5rem 1rem',
  marginBottom: '.5rem',
  backgroundColor: 'white',
  cursor: 'move'
}

const ItemTypes = {
  Coursepage: 'coursepage'
};

const coursePageSource = {
    beginDrag(props) {
        return {
            id: props.id,
            index: props.index
        }
    }
}

const coursePageTarget = {
    hover(props, monitor, component){
        const dragIndex = monitor.getItem().index;
        const hoverIndex = props.index;

        //don't replace items with themselves
        if(dragIndex === hoverIndex){
            return;
        }

        //Determine rectangle on screen
        const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();

        //get vertical middle
        const hoverMiddleY = (hoverBoundingRect.Bottom - hoverBoundingRect.Top) /2;

        //get top pixels
        const hoverClientY = clientOffset.y - hoverBoundingRect.top;

        //only perform the move when the mouse has crossed half of the items height
        //when dragging downwards, only move when the cursor is below 50%
        //when dragging upwards, only move when the cursor is above 50%

        //dragging downwards
        if(dragIndex < hoverIndex && hoverClientY < hoverMiddleY){
            return;
        }

        //dragging upwards
        if(dragIndex > hoverIndex && hoverClientY > hoverMiddleY){
            return;
        }

        //time to actually perform the action
        props.moveObject(dragIndex, hoverIndex);


    }
}

// const propTypes = {
//     connectDragSource: PropTypes.func.isRequired,
//     connectDropTarget: PropTypes.func.isRequired,
//     index: PropTypes.number.isRequired,
//     isDragging: PropTypes.bool.isRequired,
//     id: PropTypes.any.isRequired,
//     text: PropTypes.string.isRequired,
//     moveCard: PropTypes.func.isRequired
// };

function collectDropTarget(connect) {
  return {
    connectDropTarget: connect.dropTarget(),
  };
}

/**
 * Specifies which props to inject into your component.
 */
function collectDragSource(connect, monitor) {
  return {
    // Call this function inside render()
    // to let React DnD handle the drag events:
    connectDragSource: connect.dragSource(),
    // You can ask the monitor about the current drag state:
    isDragging: monitor.isDragging()
  };
}

class Coursepage extends React.Component{

    render(){
        console.log(this.props);
        const {text, isDragging, connectDragSource, connectDropTarget} = this.props;
        const opacity = isDragging ? 0 : 1;
        return connectDragSource(connectDropTarget(
                <div style={{opacity}}>
                    {text}
                </div>
        ));
    }
}
// Coursepage.propTypes = propTypes;
export default DragSource(ItemTypes.Coursepage, coursePageSource, collectDragSource)(Coursepage);
export default DropTarget(ItemTypes.Coursepage, coursePageTarget, collectDropTarget)(Coursepage);

Now the error I'm getting from this is

"Uncaught TypeError: connectDropTarget is not a function."

I console logged this.props in render and I see that connectDragSource is showing up in the this.props object but not connectDropTarget.

Can anyone tell me what I'm missing?

By the way, this is the example code I was using:

https://github.com/gaearon/react-dnd/blob/master/examples/04%20Sortable/Simple/Card.js

Upvotes: 1

Views: 3193

Answers (1)

Brad Gunn
Brad Gunn

Reputation: 191

I know this is a little old but I landed up here through google so I figured I would give it a go. First of all, you can't have two default exports as referenced here in section 3.2 http://www.2ality.com/2014/09/es6-modules-final.html

Instead you need to pass the result of one of your current default exports into the second function call - you'll see below.

This took me a couple of hours to get working as I'm also an Es6/7 newbie - so I invite any criticism!

// Container.js;
import React, { Component } from 'react';
import update from 'react/lib/update';
import Card from './Card';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';

const style = {
  width: 400
};

class Container extends Component {
  constructor(props) {
    super(props);
    this.moveCard = this.moveCard.bind(this);
    this.findCard = this.findCard.bind(this);
    this.state = {
      cards: [{
        id: 1,
        text: 'Write a cool JS library'
      }, {
        id: 2,
        text: 'Make it generic enough'
      }, {
        id: 3,
        text: 'Write README'
      }, {
        id: 4,
        text: 'Create some examples'
      }, {
        id: 5,
        text: 'Spam in Twitter and IRC to promote it (note that this element is taller than the others)'
      }, {
        id: 6,
        text: '???'
      }, {
        id: 7,
        text: 'PROFIT'
      }]
    };
  }

  findCard(id) {
    const { cards } = this.state;
    const card = cards.filter(c => c.id === id)[0];

    return {
      card,
      index: cards.indexOf(card)
    };
  }

  moveCard(id, atIndex) {
    const { card, index } = this.findCard(id);
    this.setState(update(this.state, {
      cards: {
        $splice: [
          [index, 1],
          [atIndex, 0, card]
        ]
      }
    }));
  }

  render() {
    const { cards } = this.state;
    return (
      <div style={style}>
        {cards.map((card, i) => {
          return (
            <Card key={card.id}
                  index={i}
                  id={card.id}
                  text={card.text}
                  moveCard={this.moveCard} 
                  findCard={this.findCard} />
          );
        })}
      </div>
    );
  }
}

export default DragDropContext(HTML5Backend)(Container)

Then Card.js

// Card.js
import React, { Component, PropTypes } from 'react';
import ItemTypes from './ItemTypes';
import { DragSource, DropTarget } from 'react-dnd';

const style = {
  border: '1px dashed gray',
  padding: '0.5rem 1rem',
  marginBottom: '.5rem',
  backgroundColor: 'white',
  cursor: 'move'
};

const cardSource = {
  beginDrag(props) {
    return {
      id: props.id,
      originalIndex: props.findCard(props.id).index
    };
  },

  endDrag(props, monitor) {
    const { id: droppedId, originalIndex } = monitor.getItem();
    const didDrop = monitor.didDrop();

    if (!didDrop) {
      props.moveCard(droppedId, originalIndex);
    }
  }
};

const cardTarget = {
  canDrop() {
    return false;
  },

  hover(props, monitor) {
    const { id: draggedId } = monitor.getItem();
    const { id: overId } = props;

    if (draggedId !== overId) {
      const { index: overIndex } = props.findCard(overId);
      props.moveCard(draggedId, overIndex);
    }
  }
};

function collect(connect, monitor) {
  console.log( "HERE2", connect );
  return {
    connectDropTarget: connect.dropTarget(),
    isOver: monitor.isOver(),
    canDrop: monitor.canDrop()
  };
}

function collect2(connect, monitor) {
  return {
    connectDragSource: connect.dragSource(),
    connectDragPreview: connect.dragPreview(),
    isDragging: monitor.isDragging()
  };
}

class Card extends Component {

  render() {

    const { text, isDragging, connectDragSource, connectDropTarget } = this.props;
    const opacity = isDragging ? 0 : 1;

    return connectDragSource(connectDropTarget(
      <div >
        {text}
      </div>
    ));
  }
}

Card.propTypes = {
  connectDragSource: PropTypes.func.isRequired,
  connectDropTarget: PropTypes.func.isRequired,
  isDragging: PropTypes.bool.isRequired,
  id: PropTypes.any.isRequired,
  text: PropTypes.string.isRequired,
  moveCard: PropTypes.func.isRequired,
  findCard: PropTypes.func.isRequired
};

const x = DropTarget(ItemTypes.CARD, cardTarget, collect )(Card)
export default DragSource(ItemTypes.CARD, cardSource, collect2 )( x )

And then the types include

// ItemTypes.js
export default {
  CARD: 'card'
};

Upvotes: 4

Related Questions