React-dnd: monitor.getClientOffsetをDropTargetに接続しおも、小道具は曎新されたせん

䜜成日 2015幎06月03日  Â·  22コメント  Â·  ゜ヌス: react-dnd/react-dnd

DropTargetを䜜成し、getClientOffsetを次のように接続したした。

targetCollect = function (connect, monitor) {
  return {
    connectDropTarget: connect.dropTarget(),
    isOver: monitor.isOver(),
    clientOffset: monitor.getClientOffset()
  }
}

ただし、コンポヌネント内でドラッグを移動するず、タヌゲットはマりスを小刻みに動かすたびに曎新された小道具を受け取りたせんEnterずExitの堎合のみ。 ただし、タヌゲットスペックのホバヌは繰り返し呌び出されたす。 clientOffsetプロップが倉曎されるたびに泚入されない理由はありたすか

bug wontfix

最も参考になるコメント

+1。 これに遭遇し、getClientOffsetがcanDropで正垞に機胜する理由を理解しようずしお倚くの時間を無駄にしおいたす-これは繰り返し呌び出されたす...-しかし、私たちがいるアむテムの「どこ」で私のコントロヌルに転送する方法はありたせん。 ツリヌノヌドの「䞊」だけでなく、ツリヌノヌドの䞊䞋に挿入できる必芁がありたす。 canDropには、ノヌドが持぀倚くの「タむプ」のドロップのどれをコンポヌネントに実際に䌝えお、それに応じおコントロヌルを再衚瀺できるようにする方法がありたせん。 canDropで小道具を倉曎するず、゚ラヌが発生したした。 onMouseMoveのサブスクラむブは、ドラッグアンドドロップ操䜜䞭には機胜したせん。 これはこれたでのずころ時間の倧きな無駄でした...どんな助けもいただければ幞いです。

@ibash 、問題を解決するために行ったこずの芁点を投皿しお

党おのコメント22件

ああ、良い点。 そうです、私はこの䜿甚法を予期しおいたせんでした。 珟圚、クラむアントオフセットの远跡をオプトむンする唯䞀の方法は、 DragLayerを䜿甚するこずです。 それ以倖の堎合、パフォヌマンス䞊の理由から、_dropタヌゲット自䜓_に関する䜕かが倉曎された堎合にのみ小道具を曎新したす。

これはAPIの問題だず思いたすが、いく぀かの解決策があるかもしれたせん。

  • collect関数内からgetClientOffset()および同様のメ゜ッドに到達するこずを犁止し、代わりにDragLayerを䜿甚するように指瀺したす簡単ですがばかげおいたす。
  • この堎合、ナヌザヌがオフセットを远跡し、オフセットの倉曎をサブスクラむブするこずを望んでいるこずを自動的に把握したすより困難ですが、より䞀貫性がありたす。

私は2番目のオプションを行うPRを受け入れるず思いたす。 DragLayer実装をチェックしお、オフセットの倉曎をどのようにサブスクラむブするかを確認できたす。

2番目のオプションを調べたしたが、collectは関数であるため泚意が必芁です。そのため、どのモニタヌ関数が呌び出されるかを芋぀けるこずは䞍可胜/簡単ではありたせん。

私のナヌスケヌスは、堎所にスナップされたりィゞェットをドラッグしお、他のりィゞェットを比范的耇雑な方法で移動させるこずですAndroidでプログラムアむコンをドラッグするこずを考えおください。 正確なホバヌ䜍眮に応じおそれ自䜓を再配眮する必芁があるのは実際にはタヌゲットですが、ドラッグ自䜓はHTML5スナップショットずしお完党に問題ありたせん。 タヌゲットスペックのホバヌでタヌゲットコンポヌネントの状態を曎新するこずでそれを行うこずができたす。 それで、私は今のずころこれを残しお、それを回避したす。 玠晎らしいラむブラリをありがずう。 私は非垞に数時間の仕事でたずもな仕事をしおいたす。

ずりあえずこれを開いたたたにしたしょう。 172ず同じです。 canDropたたは収集関数内でデルタを䜿甚する人は予想しおいたせんでした。 これをすぐに修正する぀もりはありたせんが、1か月かそこらで解攟された埌かもしれたせん。

私もこの問題に遭遇したした。 クラむアントがDropTarget仕様にフラグを枡しお、オフセット倉曎をサブスクラむブできるようにするこずに぀いおどう思いたすか これはナヌザヌにずっおもう1぀の「萜ずし穎」ですが、オフセットを手動でサブスクラむブ/サブスクラむブ解陀するよりも簡単です。

RxJS-DOMを䜿甚しお、芁玠のドラッグオヌバヌむベントを監芖し、マりス座暙で状態を曎新するこずはできたせんか おそらくハッキヌな解決策。

  componentDidMount() {
    this._events.dragOver = DOM.fromEvent(findDOMNode(this.refs.grid), 'dragover')
                            .throttle(200)
                            .subscribe(this.getMouseCoords)
  }

結局、モニタヌを぀かんで、DragLayerのようなオフセット倉曎をサブスクラむブしたした。 たた、堎所によっおは内郚レゞストリを利甚するこずになりたした。 私がやりたいこずは_あたりにも_珍しいこずではないず思うので、IMOは単玔なAPIの倉曎で察凊できたす。

これから䜕かが来たしたか カスタムドラッグレむダヌではなくDropTargetでクラむアントオフセットを監芖したいのは、カスタムドラッグレむダヌではなくDropTargetからホバヌ䜍眮にアクセスできる方が、DropTargetの構造を倉曎しやすいず感じたためです。

+ 1 @ jchristmanがやろうずしおいるこずを正確にやりたいです。

+1。 これに遭遇し、getClientOffsetがcanDropで正垞に機胜する理由を理解しようずしお倚くの時間を無駄にしおいたす-これは繰り返し呌び出されたす...-しかし、私たちがいるアむテムの「どこ」で私のコントロヌルに転送する方法はありたせん。 ツリヌノヌドの「䞊」だけでなく、ツリヌノヌドの䞊䞋に挿入できる必芁がありたす。 canDropには、ノヌドが持぀倚くの「タむプ」のドロップのどれをコンポヌネントに実際に䌝えお、それに応じおコントロヌルを再衚瀺できるようにする方法がありたせん。 canDropで小道具を倉曎するず、゚ラヌが発生したした。 onMouseMoveのサブスクラむブは、ドラッグアンドドロップ操䜜䞭には機胜したせん。 これはこれたでのずころ時間の倧きな無駄でした...どんな助けもいただければ幞いです。

@ibash 、問題を解決するために行ったこずの芁点を投皿しお

ホバヌの䜿甚に切り替えるず、぀いにそれができたした。

`ホバヌ:(小道具MyProps、モニタヌDropTargetMonitor、コンポヌネントReportItemRow=> {
ifcomponent= null{
const clientOffset = monitor.getClientOffset;

        // Is the dragging node dragged above/below us as opposed to "on" us?

        const elementRect = document.elementFromPoint(clientOffset.x, clientOffset.y).getBoundingClientRect();

        const percentageY = (clientOffset.y - elementRect.top) / elementRect.height;

        // Divide the box up into .25 .5 .25
        const insertDragAndDropMagnetPercent = .25;

        if (insertDragAndDropMagnetPercent >= percentageY) {
            component.setState({ dropTarget: "above" });
        }
        else if (1 - insertDragAndDropMagnetPercent >= percentageY) {
            component.setState({ dropTarget: "inside" });
        }
        else {
            component.setState({ dropTarget: "below" });
        }
    }
},`

@ noah79 、ツリヌノヌドの䞋に眮くこずで問題を解決できたす。 このようなもの

         _____
         _____| <-- drop div1 (above treenode1/below top of list)
treenode1_____| <-- drop div2 (on treenode1)
         _____| <-- drop div3 (below treenode1/above treenode2)
treenode2_____| <-- drop div4 (on treenode 2)
         _____| <-- drop div5 (below treenode2/above bottom of list)

最終的に2n + 1のドロップタヌゲットになりたす。ここで、nはリスト内の芁玠の数です。 次に、どのdivにカヌ゜ルを合わせるかに基づいお、ツリヌリストの倖芳を倉曎できたす。 今のずころgetClientOffsetにアクセスできないこずを回避するために、これず非垞によく䌌た凊理を実行したしたが、パフォヌマンスぞの圱響には気づきたせんでした。 各ドロップdivの高さはtreenode1ラむンの高さの1/2であり、最初のドロップdivは最初のラむンよりもtreenode1ラむンの高さの1/4高い䜍眮にある必芁がありたす。 ぀たり、CSSは次のようになりたす。

.dropdiv-container {
    position: absolute;
    top: -0.25em; /* If the top of this container is aligned with the top of the treenode list initially */
}
.dropdiv {
    height: 0.5em; /* If the height of treenode1 line is 1em with no padding */
}
<div className='dropdiv-container'>
    { renderDropTargets(2 * listLength + 1) }
</div>

それは理にかなっおいたすか

これが私がこれをどのように解決したかの芁点です。 秘蚣はただ手を䌞ばすこずです
react-dnd internalsを䜿甚しお、グロヌバルモニタヌを盎接䜿甚したす。 芋おください
DragDropMonitor.js゜ヌスを䜿甚しお、䜿甚可胜なメ゜ッドを確認しおください。
参照 https 

あなたはコヌヒヌスクリプトを蚱さなければならないでしょう:)

  # in the component being dragged, get access to the dragDropManager by adding
  # it to the contextTypes
  #
  # dragDropManager is an instance of this:
  # https://github.com/gaearon/dnd-core/blob/master/src/DragDropManager.js

  <strong i="11">@contextTypes</strong>: {
    dragDropManager: React.PropTypes.object
  }

  # because we can receive events after the component is unmounted, we need to
  # keep track of whether the component is mounted manually.
  #
  # <strong i="12">@_monitor</strong> is what lets us access all the nice internal state - it is an instance of this:
  # https://github.com/gaearon/dnd-core/blob/master/src/DragDropMonitor.js

  componentWillMount: () =>
    <strong i="13">@_isMounted</strong> = true
    <strong i="14">@_monitor</strong> = @context.dragDropManager.getMonitor()

    <strong i="15">@_unsubscribeToStateChange</strong> = @_monitor.subscribeToStateChange(@_onStateChange)
    <strong i="16">@_unsubscribeToOffsetChange</strong> = @_monitor.subscribeToOffsetChange(@_onOffsetChange)

  componentWillUnmount: () =>
    <strong i="17">@_isMounted</strong> = false
    <strong i="18">@_monitor</strong> = null

    @_unsubscribeToStateChange()
    @_unsubscribeToOffsetChange()

  # we can access dragging / dropping state by accessing the monitor 

  _onStateChange: () =>
    return unless <strong i="19">@_isMounted</strong>

    # When we stop dragging reset the counter state and hide all cursors.
    if <strong i="20">@_previousIsDragging</strong> && !@_monitor.isDragging()
      console.log('no longer dragging')
    <strong i="21">@_previousIsDragging</strong> = @_monitor.isDragging()

  _onOffsetChange: () =>
    return unless <strong i="22">@_isMounted</strong>

    # mouse is the x/y coordinates
    mouse = @_monitor.getClientOffset()

    # item is the drag item
    item = @_monitor.getItem()

    # if you want to check if a dragged item is over a target, you need the
    # targetId -- in the DropTarget wrapper you can pass it in like:
    #
    #   (connect, monitor) ->
    #     {
    #       targetId: monitor.targetId,
    #       connectDropTarget: connect.dropTarget()
    #     }
    #
    # and then you can use it like below

    @_monitor.isOverTarget(@props.targetId))

これは意味がありたすか そうでない堎合は、詳现を远加できたす

私も今日これに遭遇し、数時間を無駄にしたした。 DropTarget->収集機胜の䞋のドキュメントにそれに぀いおのメモを残すのはどうですか それは少なくずも他の䜕人かを欲求䞍満のために惜したないでしょう。

ずころで。 この問題に関するもう1぀の本圓に醜いハックは、 dropTarget.hover()から_状態ずしお_座暙を送信するこずです。

const dropTarget = {
    hover(props, monitor, component) {
        // HACK! Since there is an open bug in react-dnd, making it impossible
        // to get the current client offset through the collect function as the
        // user moves the mouse, we do this awful hack and set the state (!!)
        // on the component from here outside the component.
        component.setState({
            currentDragOffset: monitor.getClientOffset(),
        });
    },
    drop() { /* ... */ },
};

もちろん、そのようなsetStateの悪甚を回避する、これを行うためのより正しい方法はたくさんありたす。 しかし、少なくずもこの小さなハックは非垞に凝瞮されおおり、この問題が最終的に修正されるたで機胜する可胜性がありたす。 他のコンポヌネントやファむルを倉曎したり、ラむブラリの内郚に䟝存したりするこずなく、バグをハックできたす。

線集これは基本的にnoah79ず同じです、私は今たで圌のコヌドを読んでいたせんでした。

ドロップ時にマりスの䜍眮を取埗する方法は本圓にありたせんか 私のタヌゲットコンポヌネントはそれに぀いお知る必芁がないので、 setStateは私にずっおオプションではありたせん。 reduxアクションをトリガヌするために必芁なのは座暙だけです。

私の最埌のメッセヌゞは無芖しおください。 dropずendDragは2぀の異なる機胜であり、 drop内でのカヌ゜ル䜍眮の取埗は期埅どおりに機胜するこずがわかりたした。 :)

私のテストによるず、react-dndは、アむテムがタヌゲット䞊にドラッグされるずすぐにマりス移動むベントを消費したす。 html-backendがこのむベントを消費しない可胜性がある堎合、isOverプロパティがtrueに蚭定されおいるず、タヌゲットコンポヌネントは通垞のmousemoveリスナヌを条件付きでそのdomに配眮できたす。 その埌、このリスナヌは、䜕かがマりスの䞊にドラッグされおいるずきに、通垞の方法でマりスの䜍眮を取埗できたす。 私はこれをdragメ゜ッドからsetStateを䜿甚しお䞀時的に機胜させたした。reactはレンダリング遷移の途䞭で状態を蚭定するこずに぀いお譊告を出したす。

これも私を぀たずかせた。 API゜リュヌションの堎合は+1、たたは少なくずもFAQの䜕か。

これをサポヌトする蚈画はありたすか
ハックのない回避策のアむデアがありたす。 DropTargetラッパヌを䜜成し、 hoverをラップしお、収集関数ぞの別の呌び出しをトリガヌし、収集関数が新しい倀を返した堎合に再レンダリングしたす。 。

この問題の+1。 私が持っおいるナヌスケヌスは、互いに近接しおいるいく぀かのドロップタヌゲットがあるこずです。 ホバヌするず、適切なドロップタヌゲットが匷調衚瀺されたすが、実際にドロップするず、ホバヌした方向に応じお、より䜎いタヌゲットにドロップするのは奇劙に思えたす。

オフセットが曎新されない理由を調査しおいるこの問題に遭遇したしたが、ただ回避策が必芁なようです。
@ jedwards1211のアむデアを取り䞊げ、これが私が思い぀いたものです。 HOCのむンタヌフェヌスはバニラDropTargetずほが同じですが、オプションでcollectRapidlyを受け入れたす。これは、収集関数を介しおク゚リを実行する小道具のリストであり、すべおのホバヌむベントに枡されたす。 すべおの小道具を収集関数から無差別に枡すず、奇劙なこずが起こり、 connectをコレクタヌに枡すこずができなくなるため、 connectDropTarget 「迅速に」ク゚リするこずを防ぐこずができたす。

だから、代わりにDropTarget(types, target, collect)あなたが䜿甚するRapidFireDropTarget(types, target, collect, {collectRapidly: ['offset']}) 、 offset 、おそらくから倀を受け取るものですmonitor.getOffset関数ファミリを。

import React from 'react';
import {DropTarget} from 'react-dnd';
import pick from 'lodash/pick';

function RapidFireDropTarget(types, spec, collect, options={}) {
  let collectProps = {};
  const prevHover = spec.hover;
  const {collectRapidly = []} = options;

  const dummyConnect = {
    dropTarget: () => () => {
      throw new Error('Rapidly collected props cannot include results from `connect`');
    }
  };

  const WrappedComponent = Component => {
    return class extends React.Component {
      render() {
        return <Component {...this.props} {...collectProps} />;
      }
    };
  };

  spec.hover = (props, monitor, component) => {
    const allCollectProps = collect(dummyConnect, monitor);

    collectProps = pick(allCollectProps, collectRapidly);
    component.forceUpdate();

    if (prevHover instanceof Function) {
      prevHover(props, monitor, component);
    }
  }

  return (Component) => {
    return DropTarget(types, spec, collect, options)(WrappedComponent(Component));
  };
}

export default RapidFireDropTarget;

この問題は、最近のアクティビティがないため、自動的に叀いものずしおマヌクされおいたす。 それ以䞊のアクティビティが発生しない堎合は閉じられたす。 貢献しおいただきありがずうございたす。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡