如何将装饰器语法转换为ES6?

时间:2017-08-24 13:39:23

标签: javascript reactjs react-redux ecmascript-next react-dnd

我试图理解some code用ESnext编写的React(装饰器)。 我知道如何将装饰器从ESnext转换为ES6语法

// 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);

但我是如何将此代码转换为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>,
    ));
  }
}

2 个答案:

答案 0 :(得分:1)

因为您有两个高阶组件(HOC)装饰器,所以需要将它们组合在一起并在使用这两个(DropTarget和DragSource)导出时包装您的类。如果您正在使用redux库,那么您可以使用其效用函数compose,它结合了多个HOC并将类包装在其中。您需要关注的代码位于以下代码的末尾:

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)

或者(如果你没有使用redux)你可以将它们组合起来:

// 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))

答案 1 :(得分:1)

TypeScript文档提供了decorator composition的良好解释(TS装饰器和ES decorators proposal在大多数情况下是相同的):

  

当多个装饰器应用于单个声明时,它们的   评价类似于数学中的函数组成。在这   模型,当组成函数f和g时,得到的复合(f∘   g)(x)等于f(g(x))。

     

因此,在评估多个时执行以下步骤   TypeScript中单个声明的装饰器:

     

每个装饰器的表达式都是从上到下进行评估。

     

然后从下到上将结果称为函数。

所以它应该是:

export default DropTarget(ItemTypes.CARD, cardTarget, collectDrop)(
  DragSource(ItemTypes.CARD, cardSource, collectDrag)(Card);
);

这应该用于学术目的,而不是用于生产。原始代码不是ES6而是JSX,它仍然需要将转换器(Babel)转换为有效的JavaScript。所以没有理由不使用Babel可以提供的所有功能,包括装饰器。