如何将装饰器语法转换为 ES6?
How to convert decorator syntax to ES6?
我正在尝试理解 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>,
));
}
}
因为您有两个高阶组件 (HOC) 装饰器,所以您需要将它们组合起来并在使用这两个(DropTarget 和 DragSource)导出时包装您的 class。如果您正在使用 redux
库,那么您可以使用它的效用函数 compose
组合多个 HOC 并用它包装 class。您需要关注的代码在下面代码的末尾:
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))
TypeScript 文档提供了很好的解释 decorator composition (TS decorators and ES decorators proposal 大多数情况下是相同的):
When multiple decorators apply to a single declaration, their
evaluation is similar to function composition in mathematics. In this
model, when composing functions f and g, the resulting composite (f ∘
g)(x) is equivalent to f(g(x)).
As such, the following steps are performed when evaluating multiple
decorators on a single declaration in TypeScript:
The expressions for each decorator are evaluated top-to-bottom.
The results are then called as functions from bottom-to-top.
所以应该是:
export default DropTarget(ItemTypes.CARD, cardTarget, collectDrop)(
DragSource(ItemTypes.CARD, cardSource, collectDrag)(Card);
);
这应该用于学术目的,而不是用于生产。原始代码不是 ES6 而是 JSX,它仍然需要转译器(Babel)才能转换为有效 JavaScript。所以没有理由不使用 Babel 可以提供的所有功能,包括装饰器。
我正在尝试理解 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>,
));
}
}
因为您有两个高阶组件 (HOC) 装饰器,所以您需要将它们组合起来并在使用这两个(DropTarget 和 DragSource)导出时包装您的 class。如果您正在使用 redux
库,那么您可以使用它的效用函数 compose
组合多个 HOC 并用它包装 class。您需要关注的代码在下面代码的末尾:
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))
TypeScript 文档提供了很好的解释 decorator composition (TS decorators and ES decorators proposal 大多数情况下是相同的):
When multiple decorators apply to a single declaration, their evaluation is similar to function composition in mathematics. In this model, when composing functions f and g, the resulting composite (f ∘ g)(x) is equivalent to f(g(x)).
As such, the following steps are performed when evaluating multiple decorators on a single declaration in TypeScript:
The expressions for each decorator are evaluated top-to-bottom.
The results are then called as functions from bottom-to-top.
所以应该是:
export default DropTarget(ItemTypes.CARD, cardTarget, collectDrop)(
DragSource(ItemTypes.CARD, cardSource, collectDrag)(Card);
);
这应该用于学术目的,而不是用于生产。原始代码不是 ES6 而是 JSX,它仍然需要转译器(Babel)才能转换为有效 JavaScript。所以没有理由不使用 Babel 可以提供的所有功能,包括装饰器。