react-beautiful-dnd でドラッグ&ドロップ中のスタイルを実装する

こんにちは、Gaji-Labo アシスタントエンジニアの石垣です。

今回は、前回の記事に引き続き、ドラッグ&ドロップが可能なリストコンポーネントを作成する React 用ライブラリ react-beautiful-dnd でドラッグ&ドロップ中のスタイルを実装する方法についてまとめてみます。

react-beautiful-dnd の基本的な使用方法については前回の記事をご覧いただければと思います。

今回の記事の実装も CodeSandbox で実際に触れることができますので、こちらも是非ご覧ください。

Droppable で snapshot を使ってスタイリングをする

react-beautiful-dnd で使用するコンポーネント DroppableDraggable には、前回ご紹介した provided に加えてもう一つ snapshot という引数も用意されています。

こちらの引数は、それぞれドラッグ&ドロップ中のコンポーネントの状態を返してくれるものです。

Droppablesnapshot は以下のプロパティを持っています。ref: 公式ドキュメント

  • isDraggingOver: boolean
    リスト上でアイテムがドラッグ中かどうか
  • draggingOverWith: ?DraggableId
    リスト上でドラッグ中のアイテムの id
  • draggingFromThisWith: ?DraggableId
    ドラッグ中のアイテムの id
  • isUsingPlaceholder: boolean
    前回ご紹介した placeholder が使用されているかどうか

draggingOverWithdraggingFromThisWith の使い分けが少し分かりづらいですが、draggingFromThisWith は常にドラッグ中のアイテムの id を返すのに対し、 draggingOverWith はリストの外にアイテムを持っていくと null を返します。isDraggingOverdraggingOverWith と同様、リストからアイテムが外れると false になります。

そのため、draggingFromThisWith が null かそうでないかを判定することで、リストをアクティブにしたり非アクティブにするようなスタイルの切り替えをすることができます。

以下のサンプルは、ドラッグ中かつリスト上にアイテムがある際は背景色を lightgreen にし、リストからアイテムが外れた際は背景色を lightgrey にするスタイルを追加したものです。

リスト上にアイテムがある時は背景色が lightgreen になり、外れると lightgrey になる
<Droppable droppableId="items">
  {(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => {
    return (
      <ul
        {...provided.droppableProps}
        ref={provided.innerRef}
        style={{
          listStyleType: "none",
          background: snapshot.isDraggingOver
            ? "lightgreen"
            : snapshot.draggingFromThisWith !== null
            ? "lightgrey"
            : "white"
        }}
      >
        {state.map(({ id, content }, index) => {
          return (
            <Draggable key={id} draggableId={id} index={index}>
              {(provided: DraggableProvided) => {
                return (
                  <li
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    <div
                      style={{
                        borderBottom: "1px solid black"
                      }}
                    >
                      {content}
                    </div>
                  </li>
                );
              }}
            </Draggable>
          );
        })}
        {provided.placeholder}
      </ul>
    );
  }}
</Droppable>

Draggable で snapshot を使ってスタイリングをする

Draggablesnapshot は以下のプロパティを持っています。ref: 公式ドキュメント

  • isDragging: boolean,
    アイテムがドラッグ中かどうか
  • isDropAnimating: boolean,
    アイテムがアニメーションしているかどうか
  • dropAnimation: ?DropAnimation
    ドラッグ&ドロップ用のアニメーションについての情報
  • draggingOver: ?DroppableId,
    ドラッグしているリストの id
  • combineWith: ?DraggableId,
    アイテムが結合可能な場合、ドラッグしているアイテムの id
  • combineTargetFor: ?DraggableId,
    アイテムが結合可能な場合、結合先のアイテムの id
  • mode: ?MovementMode,
    どのモードでドラッグ&ドロップしているか
    マウス操作の際はFLUID、キーボード操作の際はSNAP が返ります

この中でドラッグ&ドロップのスタイルを行うにあたり使うのは isDragging です。isDragging を判定することで、アイテムがドラッグ中のスタイルを追加することができます。

以下のサンプルは、先程のスタイルに加え、ドラッグ中のアイテムの背景色を lightblue にするスタイルを追加したものです。

ドラッグ中のアイテムは背景色が lightblue になっている

注意点として、draggableProps が渡されている要素には react-beautiful-dnd が持つスタイルが適用されているため、インラインスタイルを追加すると動かなくなってしまいます。そのため、draggableProps が渡されている要素の子にスタイルを追加しています。

<Droppable droppableId="items">
  {(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => {
    return (
      <ul
        {...provided.droppableProps}
        ref={provided.innerRef}
        style={{
          listStyleType: "none",
          background: snapshot.isDraggingOver
            ? "lightgreen"
            : snapshot.draggingFromThisWith !== null
            ? "lightgrey"
            : "white"
        }}
      >
        {state.map(({ id, content }, index) => {
          return (
            <Draggable key={id} draggableId={id} index={index}>
              {(
                provided: DraggableProvided,
                snapshot: DraggableStateSnapshot
              ) => {
                return (
                  <li
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    <div
                      style={{
                        borderBottom: "1px solid black",
                        backgroundColor: snapshot.isDragging
                          ? "lightblue"
                          : "white"
                      }}
                    >
                      {content}
                    </div>
                  </li>
                );
              }}
            </Draggable>
          );
        })}
        {provided.placeholder}
      </ul>
    );
  }}
</Droppable>

これで react-beautiful-dnd でドラッグ&ドロップ中にスタイルを付与することが出来るようになりました。

まとめ

今回は、前回の記事に引き続き react-beautiful-dnd でドラッグ&ドロップ中のスタイルを実装する方法についてまとめました。

react-beautiful-dnd を使っている方の参考になれば幸いです。

Gaji-Laboでは、React経験が豊富なフロントエンドエンジニアを募集しています

弊社ではReactの知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違うGaji-Laboを味わいに来ませんか?

もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!

求人応募してみる!

投稿者 Ishigaki Shotaro

アシスタントエンジニアとしてHTML/CSS/JavaScriptの実装やRailsの組み込み、スタイルガイドの構築などを担当しています。 業務の中でさまざまな学びを吸収しながら、文書構造やアクセシビリティに目を向けたマークアップの学習やJavaScriptの学習などを行っています。チームに貢献できるエンジニアとなるために日々奮闘中です。