【エンジニア必見】react-draggableの使い方と実務での活用法

こんにちは、フロントエンドエンジニアのてりーです。
僕の詳しいプロフィールはこちら

・react-draggableとは何か?
・基本的な使い方と応用テクニック
・よくあるエラーとその解決策
・他のドラッグ&ドロップライブラリとの比較

React初心者の方はこちらの記事もおすすめ

関連記事

こんにちは、フロントエンドエンジニアのてりーです。 僕がReact + TypeScriptを使い始めて5年ぐらい経過しました。 大学中退してニートの時期にプログラミングを始めて、ReactとTypeScriptの分野に集中する事で[…]

では、どうぞ

1. react-draggableとは?

react-draggable GitHub公式リポジトリ

react-draggableは、Reactで簡単にドラッグ&ドロップ機能を導入するためのライブラリです。
コンポーネントをラップするだけで、すぐに実装が可能です。

主な特徴

  • 導入が簡単

  • 柔軟なカスタマイズが可能

  • CSS Transformsに基づく高パフォーマンス

2. 他のドラッグ&ドロップライブラリとの比較

2024年現在でreact-drqaggbleのライバルになりそうなのは、この辺りですかね。

  • react-dnd
  • react-beautiful-dnd

僕の勤め先ではreact-dndを使っています。

人気度

npm trendsで直近2年間のダウンロード数を見ると、react-draggableが1位です!

5年前ぐらいから去年までは圧倒的なシェアを誇っていましたが、現在は他の2つとそこまで大差はなさそうです!

次にGitHubリポジトリの情報を見て行きましょう!
Stars数では劣りますが、10年前に製造されて、去年までちゃんとメンテナンスされている事が分かります!

この図から読み取れる事として以下です。

・既存のプロジェクトではreact-draggableが使われている可能性が高い
・新規でドラッグ&ドロップライブラリを導入する際は、どれも人気度に差はないので、特徴からプロジェクトにあったものを選ぶべき

    特徴

    react-draggable

    コンポーネントをラップするだけでドラッグ&ドロップが可能になる為、導入がとても簡単!

    そして基本的なドラッグ&ドロップの機能は全て備わっている。
    CSS Transformsを使う為、既に適応されている場合は上書きされる点が注意が必要。

    react-dnd

    HTML5のドラッグ&ドロップAPIを基に構築されている為、より複雑なドラッグ&ドロップが実現出来る。
    UIコンポーネントが提供されていないので、他のライブラリに比べて理解に時間がかかるが、その分、汎用性が高く機能追加などに長く耐えうる。

    react-beautiful-dnd

    リスト内のアイテムのドラッグ&ドロップに特化している。
    逆にリストにしか使えない点が注意が必要!
    ライブラリの名前にもある通り、美しいUIが特徴!

    比較表

    ライブラリ 特徴 適した用途
    react-draggable 導入が簡単。基本的な機能は網羅 一般的なドラッグ&ドロップ
    react-dnd HTML5 APIに基づき高機能 複雑なD&D操作
    react-beautiful-dnd リスト操作に特化。UIが美しい リスト型D&D

    さて、ここからはreact-draggableを使って実例を見ていきましょう!!

    3. react-draggableの基本的な使い方

    導入手順

    基本的に以下の章に書いてある手順通りで問題ないです!

    GitHub

    React draggable component. Contribute to react-grid-layout/r…

    $ npm install react-draggable

    使い方

    実際のコードを見ながら解説していきます!
    以下のように、アイテムが画自由にドラッグ&ドロップ出来る状態を目指します!

    まずreact-draggableを使う前のコンポーネントがこちらです。

    export const Piece = () => {  
      return ( 
        <div> 
          <span>アイスクリーム</span> 
        </div>  
      ); 
    };

    1. ドラッグしたい要素を<Draggable>でラップする

    export const Piece = () => {
      return (
    
      // Draggableで要素をラップする
      <Draggable>
        <div>
          <span>アイスクリーム</span>
        </div>
      </Draggable>
      );
    };

    もうこれだけで、ドラッグアンドドロップ可能になりました!!
    めちゃくちゃ簡単でしょ!!

    4. 応用編:クリックイベントの追加

    次はクリックイベントを追加していきます。
    先ほどのアイスクリームがクリックした際に回転するようにしましょう!!

    重要なのはドラッグ&ドロップでは回転せず、アイテムをクリックした時のみ回転する!ことです。

    こんな感じですね。

    やる事は以下です!

    1. onStopでクリック時に回転する処理を追加
    2. onDragでドラッグとクリックを判別する

    onStopだけではクリック時+ドラッグ終了時に回転してしまうので、onDragでドラッグ中の判定をして、ドラッグ終了時の回転を防いでいます。

    ではやっていきましょう!

    1. onStopでクリック時に回転する処理を追加

    今回はonStopを用いています。

    理由はonStopでクリック時のアクションを実装する事で、スマホなどのタッチ操作にも対応出来るからです!

    以下のissueにてシングルクリックを検出する方法について議論されています。

    GitHub

    I have a use-case in which the draggable element can either …

    onStopだけだとクリック時と、ドラッグ終了時の両方で回転してしまうので、後ほどonDragにてドラッグ終了時を判別出来るようにします。

    コード

    export const Piece = () => {
      // useStateで回転の角度を設定する
      const [currentRotate, setCurrentRotate] = useState(0);
    
      const onStop = () => {
        setCurrentRotate(currentRotate + 90);
      };
    
      return (
        <Draggable onStop={onStop}>
        // styleで回転を要素に反映
          <div style={{ transform: "rotate(" + currentRotate + "deg)" }}>
            <span>アイスクリーム</span>
          </div>
        </Draggable>
      );
    };

    これにて、ドラッグ終了時とクリック時に要素が回転するようになったかと思います。

    2. onDragでドラッグとクリックを判別する

    onDragを使いドラッグを検知する事で、onStopでのドラッグ終了時の回転を防いでいきます。

    まずはコードを見ていきましょう!

    export const Piece = () => {
      const [currentRotate, setCurrentRotate] = useState(0);
    
      // ①ドラッグ中か否かをuseRefで持つ
      const isDraggingRef = useRef(false);
    
      // ②onDragにてisDraggingRef.current = trueを返す
      const onDrag = () => {
        isDraggingRef.current = true;
      };
    
      // ③onStopにisDraggingRefの条件分岐を入れる
      const onStop = () => {
       if(!isDraggingRef.current){
           setCurrentRotate(currentRotate + 90);
          };
          isDraggingRef.current = false;
      };
    
      return (
        <Draggable onStop={onStop} onDrag={onDrag}>
          <div style={{ transform: "rotate(" + currentRotate + "deg)" }}>
             <span>アイスクリーム</span>
          </div>
        </Draggable>
      );
    };

    順を追って解説していきます!

    ①ドラッグ中か否かをuseRefで持つ

    ここではuseRefにてドラッグ中か否かの値を管理しています。
    onStopにて参照したいだけなので、再描画など複雑な観点はいらないのでuseRefを使っています。

    Qiita

    はじめに本記事は、ReactのuseRefについて紹介する入門的記事です。公式に書いてある内容の焼き直しみたいな物なので…

    ②onDragにてisDraggingRef.current = trueを返す

    onDragはドラッグで座標の移動が発生した時に発火します!
    ですので、isDragingRef.current = trueを返しましょう!

    要素が座標移動した = ドラッグであり、クリックじゃない!という判定です。

    onStopにisDraggingRefの条件分岐を入れる

    クリックとドラッグをisDraggingRedで管理できた所で、onStopに条件分岐を加えましょう!

    これにて完成です!

    5. よくあるエラーとその解決策

    この章ではreact-draggableを実務で使っている際に起こり得るエラーとその解決法を見て行きます!

    Q1: ドラッグが機能しない

    原因: CSSのpositionの設定が不足
    解決策: 要素に position: relativeを設定
    事例: コンポーネントが absoluteになっていたため、ドラッグが正しく動作しなかった。position: relativeを追加して解決。

    Q2: タッチデバイスで動かない

    原因: タッチイベント非対応
    解決策: react-draggableのプロパティ touch-actionを確認
    事例: スマホでドラッグが効かなかったが、以下のCSSを追加することで解決

    touch-action: none;

    Q3: ドラッグ後に要素が元の位置に戻る

    原因: defaultPositionが固定されている
    解決策: defaultPositionを適切に設定する、またはpositionを明示的に管理する。

    Q4: ドラッグ中にパフォーマンスが低下する

    原因: onDragイベントの過剰な処理
    解決策: onDragハンドラをデバウンスまたはスロットリングする。

    6. よくある質問(FAQ)

    Q1: react-draggableはどのようなプロジェクトに向いていますか?

    A: シンプルなドラッグ&ドロップ機能を迅速に導入したいプロジェクトに最適です。
    特に小規模プロジェクトプロトタイプ開発で力を発揮します。

    Q2: タッチ操作はサポートされていますか?

    A: はい、タッチデバイスにも対応しています。
    touch-action: noneを設定して下さい!

    Q3: react-dndとの違いは?

    A: react-dndは複雑なドラッグ&ドロップ操作に向いています。
    詳しい違いはこちらの比較表を参考にして下さい!

    ライブラリ 特徴 適した用途
    react-draggable 導入が簡単。基本的な機能は網羅 一般的なドラッグ&ドロップ
    react-dnd HTML5 APIに基づき高機能 複雑なD&D操作
    react-beautiful-dnd リスト操作に特化。UIが美しい リスト型D&D

     

    まとめ

    react-draggableの基本情報や、使い方は理解出来たでしょうか?

    僕は普段からReact関連の発信をしているので、良かったら他の記事もご覧になって下さい。

    ReactかVue.sjのどちらをメインするかで迷ってる方へ
    関連記事

    読者 ・エンジニアになりたいけど、どの言語を学ぶか迷っている ・React、Vue.jsのどちらを学ぶか迷ってる ・将来性や年収も知りたい てりー そんな疑問に対して、解説します。 […]

    Reactを実務レベルまでマスターする勉強法
    関連記事

    こんにちは、フロントエンドエンジニアのてりーです。 僕がReact + TypeScriptを使い始めて5年ぐらい経過しました。 大学中退してニートの時期にプログラミングを始めて、ReactとTypeScriptの分野に集中する事で[…]

    フロントエンドでキャリアアップを考えているなら
    関連記事

    こんにちは、フロントエンドエンジニアのてりーです。 僕の詳しいプロフィールはこちら 今回は大学中退してニートだった自分が完全未経験からメガベンチャーに入社した方法について解説していきます。 ・完全未経験から将来的なメガベンチャー転[…]