react-sortablejs 实现多级嵌套拖动和数据更新

781 阅读1分钟

通过react-sortablejs库实现多级嵌套拖动,拖动后实时更新全量数据。支持跨级别拖动。

接口声明

interface Item {
  id: string
  content: string
  children?: Item[]
}

interface SortListProps {
  items: Item[]
  list: Item[]
  setItems: React.Dispatch<React.SetStateAction<Item[]>>
  parentIds?: string[]
}

SortList组件

const SortList: React.FC<SortListProps> = ({ list, items, setItems, parentIds }) => {
  const setList = (list: Item[]) => {
    const _parentIds = [...(parentIds || [])]

    if (_parentIds.length > 0) {
      setItems((prevItems) => {
        const _items = [...prevItems]

        const updateChild = (_list: Item[]) => {
          const parentId = _parentIds.shift()
          const parent = _list.find((item) => item.id === parentId)

          if (_parentIds.length && parent) {
            updateChild(parent.children || [])
          } else if (parent) {
            parent.children = list
          }
        }

        updateChild(_items)

        return _items
      })
    } else {
      setItems((_list) => {
        _list = list
        return [..._list]
      })
    }
  }

  return (
    <ReactSortable
      group="nested"
      animation={150}
      fallbackOnBody
      swapThreshold={0.65}
      list={list}
      setList={setList}
      tag="ul"
    >
      {list.map((item) => (
        <li key={item.id}>
          <span className="handle"></span> {item.content}
          {item.children && item.children.length > 0 && (
            <SortList
              parentIds={[...(parentIds || []), item.id]}
              list={item.children}
              items={items}
              setItems={setItems}
            />
          )}
        </li>
      ))}
    </ReactSortable>
  )
}

调用组件

const App: React.FC = () => {
  const nestedItems: Item[] = [
    {
      id: 'item-1',
      content: 'Item 1',
      children: [
        {
          id: 'nested-1',
          content: 'Nested 1',
          children: [
            { id: 'nested-1-1', content: 'Nested 1-1' },
            { id: 'nested-2-1', content: 'Nested 2-1' },
          ],
        },
        { id: 'nested-2', content: 'Nested 2' },
      ],
    },
    {
      id: 'item-2',
      content: 'Item 2',
      children: [
        { id: 'nested-3', content: 'Nested 3' },
        { id: 'nested-4', content: 'Nested 4' },
      ],
    },
  ]

  const [list, setList] = useState<Item[]>(nestedItems)

  return <SortList list={list} items={list} setItems={setList} />
}

export default App