You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为react-sortablejs实现虚拟化?解决react-virtuoso被识别为单个排序项问题

解决react-sortablejs与react-virtuoso结合时的排序项定位问题

问题核心在于你当前的结构中,ReactSortable直接包裹整个Virtuoso组件,而Virtuoso内部会生成独立的列表DOM结构,导致ReactSortable只能识别最外层容器为单个可排序项,无法穿透到内部的li元素。

以下是两种可行的解决方案:

方案一:替换Virtuoso的列表容器为ReactSortable

通过Virtuoso的components属性,将默认的列表组件替换为ReactSortable,让它直接管理每个渲染的li项,同时保留虚拟化能力:

import ReactSortable from 'react-sortablejs';
import { Virtuoso } from 'react-virtuoso';
import { useState } from 'react';

function SortableVirtualList() {
  const [items, setItems] = useState(Array.from({ length: 500 }, (_, i) => `Item ${i}`));

  const handleSortEnd = (evt) => {
    const { oldIndex, newIndex } = evt;
    // 更新数据源顺序
    const newItems = [...items];
    const [movedItem] = newItems.splice(oldIndex, 1);
    newItems.splice(newIndex, 0, movedItem);
    setItems(newItems);
  };

  return (
    <Virtuoso
      totalCount={items.length}
      components={{
        // 替换默认的ul为ReactSortable
        List: (props) => (
          <ReactSortable
            tag="ul"
            {...props}
            animation={150}
            onEnd={handleSortEnd}
            // 其他sortable配置项
          />
        ),
        // 自定义列表项组件
        Item: (props) => <li {...props}>{items[props.index]}</li>
      }}
    />
  );
}

这种方式完全贴合Virtuoso的渲染逻辑,ReactSortable直接作为列表容器,能准确识别每个动态渲染的li项,虚拟化和排序功能互不干扰。

方案二:指定ReactSortable的可拖动选择器

如果不想修改Virtuoso的默认组件结构,可以给ReactSortable设置draggable属性,指定内部可拖动元素的选择器:

import ReactSortable from 'react-sortablejs';
import { Virtuoso } from 'react-virtuoso';
import { useState } from 'react';

function SortableVirtualList() {
  const [items, setItems] = useState(Array.from({ length: 500 }, (_, i) => `Item ${i}`));

  const handleSortEnd = (evt) => {
    const { oldIndex, newIndex } = evt;
    const newItems = [...items];
    const [movedItem] = newItems.splice(oldIndex, 1);
    newItems.splice(newIndex, 0, movedItem);
    setItems(newItems);
  };

  return (
    <ReactSortable
      tag="div"
      draggable=".sortable-item"
      animation={150}
      onEnd={handleSortEnd}
    >
      <Virtuoso
        totalCount={items.length}
        itemContent={(index) => (
          <li className="sortable-item">{items[index]}</li>
        )}
      />
    </ReactSortable>
  );
}

注意:这种方式需要确保ReactSortable能正确选中Virtuoso动态渲染的li元素,由于虚拟化列表只会渲染可见项,部分场景下可能不如方案一稳定。

关键注意事项

  • 无论哪种方案,排序结束后都必须更新数据源的顺序,因为Virtuoso的渲染完全依赖数据源的状态
  • 确保ReactSortable的tag属性与Virtuoso默认的列表标签(默认是ul)匹配,避免DOM结构冲突

内容的提问来源于stack exchange,提问作者Nameer Muhammad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 07:25:24