drop(props, monitor, component)
メソッドには、3つの引数があります。 しかし、 canDrop(props, monitor)
には、 component
引数はありません。
アイテムを別のコンポーネントの上にドラッグしたときに、そのコンポーネントを50%(高さ)の2つの部分に「分割」したいと思います。 アイテムが上部にドロップされた場合はその上に配置され、下部にドロップされた場合は後に配置されます。
コンポーネントが上部/下部にドロップされているかどうかを検出するコードはすでにあります。 ここで必要なのは、マウスが上部/下部にあるかどうかに基づいてクラスを追加することです(ただし、ドロップアクションではなく、ホバーアクション中に)。
hover(props, monitor, component)
メソッドを使用できるかどうかわかりません。これは、コンポーネントにプロパティを追加する方法がわからないためです(DOMなどにCSSクラスを追加します)。これは、コンポーネント自体に属していないため、コンテキストなどにアクセスできないためです。
何かが足りないと思います。 :)
ねえ、あなたは運がいいです! 私は以前にこれをほぼ正確に実装したことがあるので、いくつかのコードをまとめましょう。
さて、コンポーネントに状態を設定し、状態が設定されたらクラスを追加するという考え方です。
Fooをバーにドラッグしているとしましょう。
import React, { Component } from "react";
import classNames from "classnames";
class Bar extends Component {
constructor(props) {
super(props);
this.state = {
// Where a foo is hovering over the component. One of null, "above", or "below"
fooHover: null,
};
}
render() {
const { fooHover } = this.state;
const classes = classNames("bar", {
"bar-above": fooHover === "above",
"bar-below": fooHover === "below",
});
}
}
唯一の問題は、その状態をどのように設定するかです。
import { findDOMNode } from "react-dom";
const barTarget = {
...
hover(props, monitor, component) {
if (!monitor.canDrop()) {
return;
}
const rawComponent = undecorate(component); // undecorate described below
const { y } = monitor.getClientOffset();
const { top, height } = findDOMNode(component).getBoundingClientRect();
if (y < top + height/2) {
rawComponent.setFooHover("above"); // setFooHover described below
} else {
rawComponent.setFooHover("below");
}
},
...
}
したがって、基本的には、コンポーネントのインスタンスメソッドsetFooHover
を呼び出します。これにより、 setState
が呼び出されます。 パフォーマンス上の理由から、次のようになります。
// In Bar
setFooHover(fooHover) {
if (fooHover !== this.state.fooHover) {
this.setState({ fooHover });
}
}
上記でundecorate
と呼んでいる理由は、react-dndがより高次のコンポーネントを使用しており、ラップされていないコンポーネントが必要だからです。 私の意見では、これは高次コンポーネントの醜い複雑さです。 代わりに、フラックスストアなどにアクションをディスパッチすることでこれを実装できますが、私のように実行することにした場合は、ここに私のundecorate
ます。
function undecorate(component) {
let curr = component;
while (typeof curr.getDecoratedComponentInstance === "function") {
curr = curr.getDecoratedComponentInstance();
}
return curr;
}
これを実装すると、1つの小さな問題を除いて、すべてが良好に見えます。 クラスは決して消えません! setHoverState(null)
呼び出す人は誰もいません(barTargetにendHover関数などはありません)。 これを処理する適切な方法は、次のようにcomponentWillReceiveProps
を使用することです。
componentWillReceiveProps(nextProps) {
if (this.props.isFooOver && !nextProps.isFooOver) {
this.setState({ fooHover: null });
}
}
(収集関数に{ isFooOver: monitor.isOver() }
を追加することを忘れないでください)
どうなるか教えてください!
詳細な説明ありがとうございます! 知らせます :)
最後に、Reduxアプローチを使用したので、基本的に、ドロップイベントが発生したときに、レデューサーを介してイベントをディスパッチしました。
drop: (propsTargetItem, monitor, targetItem) ->
draggedItem = monitor.getItem()# Item that has been dragged and eventually dropped.
coordsDrop = monitor.getClientOffset()# Coords of the drop action.
diff = monitor.getDifferenceFromInitialOffset()# Comparison of the initial click (dragging start) against the end of the click (dropping start).
patternId = draggedItem.patternId
patternPosition = draggedItem.position
targetId = propsTargetItem.context.patternId
targetPosition = propsTargetItem.context.position
isCursorAboveHalf = GeoService.isAboveHalf(ReactDOM.findDOMNode(targetItem), coordsDrop.y)
# Extract positions in the array of children.
oldPosition = draggedItem.position# Current position of the item, which will be the old position as soon as the item is moved. (by the server through sockets)
newPosition = calcDropPosition(targetId, patternId, patternPosition, targetPosition, isCursorAboveHalf)# Position where we will move the dragged item.
# Dispatch only if the position has changed and is set.
if oldPosition isnt newPosition and newPosition?
draggedItem.moveDnDPattern(Object.assign({}, draggedItem, {newPosition: newPosition, oldPosition: oldPosition}))
最も参考になるコメント
さて、コンポーネントに状態を設定し、状態が設定されたらクラスを追加するという考え方です。
Fooをバーにドラッグしているとしましょう。
唯一の問題は、その状態をどのように設定するかです。
したがって、基本的には、コンポーネントのインスタンスメソッド
setFooHover
を呼び出します。これにより、setState
が呼び出されます。 パフォーマンス上の理由から、次のようになります。上記で
undecorate
と呼んでいる理由は、react-dndがより高次のコンポーネントを使用しており、ラップされていないコンポーネントが必要だからです。 私の意見では、これは高次コンポーネントの醜い複雑さです。 代わりに、フラックスストアなどにアクションをディスパッチすることでこれを実装できますが、私のように実行することにした場合は、ここに私のundecorate
ます。これを実装すると、1つの小さな問題を除いて、すべてが良好に見えます。 クラスは決して消えません!
setHoverState(null)
呼び出す人は誰もいません(barTargetにendHover関数などはありません)。 これを処理する適切な方法は、次のようにcomponentWillReceiveProps
を使用することです。(収集関数に
{ isFooOver: monitor.isOver() }
を追加することを忘れないでください)どうなるか教えてください!