2

我试图理解一些用 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>,
    ));
  }
}
4

2 回答 2

1

TypeScript 文档对装饰器组合提供了很好的解释(TS 装饰器和ES 装饰器提案在很大程度上是相同的):

当多个装饰器应用于单个声明时,它们的评估类似于数学中的函数组合。在这个模型中,当组合函数 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 可以提供的所有功能,包括装饰器。

于 2017-08-24T14:00:24.807 回答
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))
于 2017-08-24T13:53:19.350 回答