web-dev-qa-db-ja.com

React DnD:findDOMNodeの使用を避けます

私は完全には理解していませんが、どうやら findDOMNode() の使用は推奨されていません。

ドラッグアンドドロップコンポーネントを作成しようとしていますが、コンポーネント変数からrefにアクセスする方法がわかりません。これは私が現在持っているものの例です:

const cardTarget = {
    hover(props, monitor, component) {
        ...
        // Determine rectangle on screen
        const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();
        ...
    }
}

ソース

編集

this example では機能しないが this one では機能しないため、コンポーネントがドラッグアンドドロップのソースとターゲットの両方であることが原因である可能性があります。

15
joshhunt

Es6クラスの構文とReact(執筆時点では15)の最新バージョンを使用していると仮定すると、共有したリンクにDanの例のようにコールバック参照を添付できます。 the docs から:

HTML要素でref属性が使用されている場合、refコールバックは、基になるDOM要素を引数として受け取ります。たとえば、次のコードはrefコールバックを使用して、DOMノードへの参照を格納します。

_<h3
    className="widget"
    onMouseOver={ this.handleHover.bind( this ) }
    ref={node => this.node = node}
>
_

次に、以前の友人findDOMNode()またはgetDOMNode()と同じようにノードにアクセスできます。

_handleHover() {
  const rect = this.node.getBoundingClientRect(); // Your DOM node
  this.setState({ rect });
}
_

動作中: https://jsfiddle.net/ftub8ro6/

編集:

React DNDは舞台裏で少し魔法をかけるので、装飾されたコンポーネントを取得するためにAPIを使用する必要があります。それらは getDecoratedComponentInstance() を提供します基礎となるコンポーネントを取得できます。これを使用すると、期待どおりに_component.node_を取得できます。

_hover(props, monitor, component) {
    const dragIndex = monitor.getItem().index;
    const hoverIndex = props.index;
    const rawComponent = component.getDecoratedComponentInstance();
    console.log( rawComponent.node.getBoundingClientRect() );
    ...
_

ここでそれは動作しています:

https://jsfiddle.net/h4w4btz9/2/

20
imjared

より良いソリューション

より良い解決策は、ドラッグ可能なコンポーネントをdivでラップし、それに参照を定義して、それをドラッグ可能なコンポーネントに渡すことです。

_<div key={key} ref={node => { this.node = node; }}>
  <MyComponent
    node={this.node}
  />
</div>
_

MyComponentDragSourceでラップされています。今すぐ使用できます

_hover(props, monitor, component) {
  ...
  props.node && props.node.getBoundingClientRect();
  ...
}
_

(_props.node &&_は、未定義のオブジェクトでgetBoundingClientRectを呼び出さないようにするために追加されただけです)

findDOMNodeの代替

ラッピングdivを追加したくない場合は、次のようにします。 @imjaredと ここで提案する解決策 の応答は機能しません(少なくとも_[email protected]_および_[email protected]_では)。

findDOMNodeを使用しないfindDOMNode(component).getBoundingClientRect();の唯一の有効な代替方法は次のとおりです。

_hover(props, monitor, component) {
  ...
  component.decoratedComponentInstance._reactInternalInstance._renderedComponent._hostNode.getBoundingClientRect();
  ...
}
_

これはあまり美しくなく、危険ですreactは将来のバージョンでこの内部パスを変更する可能性があるためです!

その他(弱い)代替

正確な値は得られませんが、小さなdragSourceがある場合は、おそらく十分なmonitor.getDifferenceFromInitialOffset();を使用してください。その後、戻り値は、dragSourceのサイズに応じて小さなエラーマージンでかなり予測可能です。

2
Andru

React-DnDのAPIは非常に柔軟です。これを(ab)使用できます。

たとえば、React-DnDでは、基になるコンポーネントに渡されるコネクタを特定できます。つまり、それらをラップすることもできます。 :)

たとえば、ターゲットコネクタをオーバーライドして、ノードをモニターに保存します。 Symbolを使用して、この小さなハックを外部に漏らさないようにします。

const NODE = Symbol('Node')

function targetCollector(connect, monitor) {
  const connectDropTarget = connect.dropTarget()
  return {
    // Consumer does not have to know what we're doing ;)
    connectDropTarget: node => {
      monitor[NODE] = node
      connectDropTarget(node)
    }
  }
}

hoverメソッドで、次を使用できます

const node = monitor[NODE]
const hoverBoundingRect = node.getBoundingClientRect()

このアプローチは、React-DnDのフローに便乗し、Symbolを使用して外部の世界を保護します。

このアプローチを使用する場合でも、クラスベースのthis.node = node refアプローチを使用する場合でも、基になるReactノードを使用します。コンシューマがReact-DnDで既に必要とされているもの以外のrefを手動で使用することを忘れないでください。また、コンシューマーもクラスコンポーネントである必要はありません。

0
Jeff