メインコンテンツまでスキップ

useDrag

要素の上のポインタのドラッグを追跡し、どれだけ動いたかを報告します。

Source

この hook は ref callback を返します。ドラッグの起点になる要素に付ければ、あとはハンドラが受け取ります。持つべき state も、後片付けもありません。

Loading...
function App() {
  const [position, setPosition] = useState({ x: 0, y: 0 })
  const [delta, setDelta] = useState({ x: 0, y: 0 })
  const [dragging, setDragging] = useState(false)

  const dragRef = useDrag<HTMLDivElement>({
    cursor: 'grabbing',
    onDragStart: () => setDragging(true),
    onDragEnd: () => setDragging(false),
    onDrag: (x, y, deltaX, deltaY) => {
      setPosition({ x, y })
      setDelta({ x: deltaX, y: deltaY })
    },
  })

  return (
    <div style={{ userSelect: 'none' }}>
      <div
        ref={dragRef}
        style={{
          padding: '2rem',
          marginBottom: '0.5rem',
          border: '1px solid currentColor',
          borderRadius: 8,
          textAlign: 'center',
          touchAction: 'none',
        }}
      >
        Drag here
      </div>
      <div>dragging: {String(dragging)}</div>
      <div>
        x: {position.x}, y: {position.y}
      </div>
      <div>
        deltaX: {delta.x}, deltaY: {delta.y}
      </div>
    </div>
  )
}

インポート​

import { useDrag } from '@tremolo-ui/react'

この hook が引き受けること​

ポインタを捕捉するので、要素の外へ出てもドラッグは続きます。 ボックスの外、ウィンドウの外、ページの外へ出ても報告は続き、離したところで終わります。要素自身で pointermove を購読すると、ポインタが出た時点で終わってしまいます。

threshold が、クリックをドラッグとして数えないようにします。 クリックでもポインタは 1〜2 ピクセル動くので、しきい値が無いとダブルクリックの 2 回の押下の間がドラッグとして報告されます。しきい値に満たない移動は捨てずに次へ繰り越すので、ゆっくりしたドラッグも積み上がれば報告されます。

onDragStart は pointerdown ではなく、ドラッグが始まった時点で呼ばれます。 しきい値を超えた瞬間で、cursor が当たるのも同じタイミングです。

CSS で要素に touch-action: none を付けてください。付けないと、ブラウザがドラッグを通す代わりにページをスクロールします。

修飾キーを読む​

どのハンドラも最後の引数に DragState 全体を受け取り、その中にポインタイベントが入っています。修飾キーはそこにあります。

useDrag({
onDrag: (x, y, deltaX, deltaY, state) => {
const step = state.event.shiftKey ? 0.1 : 1
},
})

ポインタではなく値を動かす​

useDrag が報告するのはピクセルです。範囲・step・スケールを持つ数値が欲しいときは useDragValue を使ってください。この hook の上に作られていて、マッピングまで面倒を見ます。

オプション​

Prop型既定値
thresholdnumber1
cursorstring—
pointerLockbooleanfalse
onDrag(x: number, y: number, deltaX: number, deltaY: number, state: DragState) => void—
onDragStart(state: DragState) => void—
onDragEnd(state: DragState) => void—

すべての説明: UseDragOptions