nabeliwonote

react-dnd で isDragging が正しい値を返さないとき

react-dnd という React でドラッグ&ドロップを実装したいときに使われる鉄板ライブラリがあります。
これを使っていたときに isDragging の挙動で若干ハマったのでメモ。

isDragging is 何

ドラッグ&ドロップするとき、自分が今掴んでいるコンポーネントはマウスについてくるようになってる。
で実際の挙動がどうなっているかというと、そのとき掴んでいるコンポーネントのコピーをマウスに追随させて、オリジナルの方はそのまま元あった場所に残っている状態になっている。だけどそれだと画面上に同じコンポーネントが2つ表示されていることになってわかりづらいので、その場にとどまっているオリジナルの方は opacity を変えて透明にしている。
っていう挙動を実現するために、今掴んでいるコンポーネントかどうかっていう論理値を得るために isDragging っていうメソッドが react-dnd では用意されている。

具体的な使い方は公式の example にある。
react-dnd/Card.js at master · react-dnd/react-dnd

ハマったこと

今回ハマった状況は、コンポーネントを掴んで動かして位置が変わって props の変更が行われたあと、この isDragging が正しい値を返さずに、掴んでいるコンポーネントで false を、掴んでいなくて場所の入れ替えが行われたコンポーネントで true を返してしまうという感じ。

こうなると掴んでるコンポーネントは元の位置のものとマウスに追随するものとで2つ表示されてしまい、影響を受けて位置が変わったコンポーネントは透明になって消えてしまうっていうわけのわからない挙動になる。

原因

Issue があった。解決済。
isdragging doesn’t seem to be updating correctly · Issue #748 · react-dnd/react-dnd

Issue があって解決策もわかってるならわざわざ記事にする必要ないじゃんって話なんだけれど、記事にしようと思った段階では見つけてなかったっていうのと、あとまあ解決策見つけたけれど英語だし一応日本語記事にしといて意味ないこともないかということで。

どういうことが起きてたかというと、ドラッグを開始するときに beginDrag というメソッドを定義しておく必要があるんだけれど(先にあげた example に記述あり)、このメソッドで返すオブジェクトに含まれている id というキーと同じ値を、ドラッグ&ドロップ対象のコンポーネントの key とマッチさせる必要があって、それがマッチしていないと isDragging の値が更新されないという結果になる。

僕がなんでこれにハマってしまったかというと、コンポーネントに渡す値に order というコンポーネントの表示順を管理する数値を渡してあって、コンポーネントのキーにデータの id ではなく order を渡してしまっていたがために起きた挙動でした。

通常はサーバー側で DB 叩いて渡されるデータの id をキーに渡すのが当たり前なので普通に考えたら起こりえないはずなんだけれどちょっとミスるとこういう挙動になるよって感じで。
ただこれは react-dnd のドキュメントに記載されていない動きなのでハマるとちょっと悩むかなってところでした。

まあコンポーネントの key に変なもの渡すなって話ですね。