Search code examples
javascriptreactjsreact-reduxecmascript-nextreact-dnd

How to convert decorator syntax to ES6?


I am trying to understand some code React written in ESnext (decorators). I know how to convert decorators from ESnext to ES6 syntax

// ESnext
function collect(connect, monitor) {
  return {
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging()
  }
}

@DragSource(Types.CARD, cardSource, collect)
export default class Card extends React.Component {
  render() {
    const { id } = this.props;
    const { isDragging, connectDragSource } = this.props;

    return connectDragSource(
      <div>
        I am a draggable card number {id}
        {isDragging && ' (and I am being dragged now)'}
      </div>
    );
  }
}

ES6

// ES6
function collect(connect, monitor) {
  return {
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging()
  };
}

class Card extends React.Component {
  render() {
    const { id } = this.props;
    const { isDragging, connectDragSource } = this.props;

    return connectDragSource(
      <div>
        I am a draggable card number {id}
        {isDragging && ' (and I am being dragged now)'}
      </div>
    );
  }
}

export default DragSource(Types.CARD, cardSource, collect)(Card);

But I'm stuck how to convert this code to ES6 ?

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

function collectDrag(connect, monitor) {
  return {
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging()
  };
}

@DropTarget(ItemTypes.CARD, cardTarget, collectDrop)
@DragSource(ItemTypes.CARD, cardSource, collectDrag)
export default class Card extends Component {
  static 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,
  };

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

    return connectDragSource(connectDropTarget(
      <div style={{ ...style, opacity }}>
        {text}
      </div>,
    ));
  }
}

Solution

  • Because you have two Higher Order Component (HOC) decorators you need to combine them and wrap your class when exporting with these two (DropTarget and DragSource). If you're using redux library then you can use its utility function compose that combines multiple HOCs and wraps the class with it. The code you need to focus on is at the end of the code below:

    import { compose } from 'redux'
    
    function collectDrop(connect) {
      return {
        connectDropTarget: connect.dropTarget(),
      };
    }
    
    function collectDrag(connect, monitor) {
      return {
        connectDragSource: connect.dragSource(),
        isDragging: monitor.isDragging()
      };
    }
    
    class Card extends Component {
      static 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,
      };
    
      render() {
        const { text, isDragging, connectDragSource, connectDropTarget } = this.props;
        const opacity = isDragging ? 0 : 1;
    
        return connectDragSource(connectDropTarget(
          <div style={{ ...style, opacity }}>
            {text}
          </div>,
        ));
      }
    }
    
    const enhance = compose(
      DropTarget(ItemTypes.CARD, cardTarget, collectDrop),
      DragSource(ItemTypes.CARD, cardSource, collectDrag)
    )
    
    export default enhance(Card)
    

    Or (if you're not using redux) you can combine them like that:

    // Comment this part out
    /* const enhance = compose(
      DropTarget(ItemTypes.CARD, cardTarget, collectDrop),
      DragSource(ItemTypes.CARD, cardSource, collectDrag)
    )
    
    export default enhance(Card)*/
    
    // and change to this
    
    const dropTargetHOC = DropTarget(ItemTypes.CARD, cardTarget, collectDrop)
    const dragSourceHOC = DragSource(ItemTypes.CARD, cardSource, collectDrag)
    
    export default dropTargetHOC(dragSourceHOC(Card))