0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【dnd-kit】グローバルSortableContextだけでは足りないDnDアニメーション不具合の解決法

0
Posted at

はじめに

セクション分けされたリストにおけるDndを@dnd-kitで実装するとき、グローバルな SortableContext を定義しているのに、なぜ各セクション内にも必要なのか? という疑問が生まれると思います。
直感的には全アイテムIDを含むグローバル SortableContext があれば十分のように思えますが、グローバルのみではアニメーションにガタつきが発生してしまいます。

本記事では、その原因と「グローバル」と「ローカル」の二重構造による解決策を解説します。

問題の構造

グローバルな SortableContext を定義し、セクションごとに DroppableContainer を配置するだけでは、ドラッグ時にアニメーションがガタつく問題が発生します。

// NG: セクション内にSortableContextがない
<SortableContext items={allItemIds}>
  {sections.map(([section, items]) => (
    <div key={section}>
      <DroppableContainer id={section}>
        {items.map(item => <SortableItem item={item} />)}
      </DroppableContainer>
    </div>
  ))}
</SortableContext>

原因

SortableContext には2つの役割があります

  1. 異なるコンテキスト間でのドラッグ認識(グローバル)
  2. 同一コンテキスト内でのアニメーション計算(ローカル)

グローバルだけではドラッグ可能なアイテムの認識はできても、セクション内での位置関係を正しく計算できません。

解決策

各セクション内にもローカルな SortableContext を追加します。

// OK: セクション内にもSortableContextを追加
<SortableContext items={allItemIds}>
  {sections.map(([section, items]) => (
    <div key={section}>
      <SortableContext items={items.map(item => `sortable-item-${item.id}`)}>
        <DroppableContainer id={section}>
          {items.map(item => <SortableItem item={item} />)}
        </DroppableContainer>
      </SortableContext>
    </div>
  ))}
</SortableContext>

なぜこれで動くのか

  • グローバル:セクション間のドラッグを可能にする
  • ローカル:セクション内でのアニメーション計算を正しく行う

@dnd-kit/sortable は最も近い祖先の SortableContext から情報を取得するため、この二重構造でクロスセクションのドラッグとスムーズなアニメーションを両立できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?