1
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?

SortableJS でフォルダ並び替えを実装したら、先頭と末尾だけ動かないように見えた原因は state 更新漏れだった

1
Last updated at Posted at 2026-04-14

SortableJS 利用時に起きる「端だけ戻る」不具合を避ける

SortableJS で並び替えを実装したとき、ログ上は順序変更が進んでいるように見えても、画面更新後に先頭・末尾だけ元に戻ることがあります。原因は多くの場合、ライブラリそのものではなく、保存・復元フローの設計です。

よく起こる症状

  • 縦ツリーの先頭/末尾だけ順序が戻る
  • 横並びで左右端だけ戻る
  • sortable_reorder などのログは出るのに UI が元に戻る

原因の本質

  • SortableJS は「DOM の移動」を起点としてイベントを発生させる
  • ただし最終表示は state(内部状態)を経由して再描画される
  • 保存順と内部状態の反映が経路ごとに分裂すると、再読込時に整合しやすい
  • ツリー構造では特に、親グループを跨ぐ比較ソートより、対象親の子配列を再構成したほうが安全

対策の原則

  • 並び替え確定時は必ず orderedPaths を1種類の順序として確定する
  • onEnd, edge drop, 補助移動など、経路が違っても同一の状態更新関数へ集約する
  • 端点移動も orderedPaths に含め、親単位で state を再構成する
  • 再読込時は保存順を同じ再構成関数で state に反映してから描画する

実装例(要点)

function applyOrderToState(parent, orderedPaths) {
  const siblings = state.folderTree.filter((entry) => (entry.parent || "") === parent);
  const byPath = new Map(siblings.map((entry) => [entry.path, entry]));
  const ordered = [];
  const used = new Set();

  for (const path of orderedPaths) {
    if (!byPath.has(path) || used.has(path)) continue;
    ordered.push(byPath.get(path));
    used.add(path);
  }

  for (const entry of siblings) {
    if (!used.has(entry.path)) ordered.push(entry);
  }

  const nextTree = [];
  let inserted = false;
  for (const entry of state.folderTree) {
    if ((entry.parent || "") === parent) {
      if (!inserted) {
        nextTree.push(...ordered);
        inserted = true;
      }
      continue;
    }
    nextTree.push(entry);
  }
  if (!inserted) nextTree.push(...ordered);

  state.folderTree = nextTree;
}

まとめ

端だけ戻る不具合は、SortableJS の検知失敗というより 保存→state反映→再描画の整合性不足 が本体です。
並び順は orderedPaths を唯一の正として扱い、すべての経路を同一関数で state に反映・復元する設計にすると再発を抑えられます。

1
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
1
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?