react-dnd指南

1,110 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

前言

react拖拽库有很多:react-dnd、react-draggable、react-beautiful-dnd、smooth-dnd;但是他们各有各的优缺点;

react-beautiful-dnd交互做的很好,性能优化到了极致;但是无法单独设置一个只可以往外拖拽的元素,扩展性比较差

react-draggable功能比较局限

react-dnd只提供底层API,我们还是需要去处理复杂数据交换,扩展性高,但是理解和使用起来非常复杂,它的作者同时也是redux的作者

smooth-dnd是一个关注度很小的一个库,但是它功能齐全

我们今天就选择最难的react-dnd介绍一下,因为看过文档都不一定会用,而其他几个库基本上照着文档操作就行了

首先需要安装两个依赖:npm i -S react-dnd react-dnd-html5-backend

Provider

首先我们回忆一下redux的用法:需要先在最外层包裹一个Provider,类似的react-dnd也需要这样操作:

import { HTML5Backend } from 'react-dnd-html5-backend'
import { DndProvider } from 'react-dnd'
import {Component} from 'react'


export default class Layout extends Component {
  render() {
    retuen(
      <div class='layout'>
        <DndProvider backend={HTML5Backend}>{this.props.children}</DndProvider>
      </div>
    )
  }
}

react-dnd有hooks API和class API两种,但是class API难以理解而且用起来十分反人类,所以我们就不介绍了

hooks API

useDrag

我们看一个这个函数的签名:

image.png

第一个参数:item,item.type指定拖拽的ID,到时候到useDrag里面也需要使用,它是一个唯一拖拽ID,只有ID匹配的元素才能拖放

begin函数:参数是DragSourceMonitor,这个对象里面可以拿到所有拖拽元素的数据,我们可以做一些状态初始化的工作;对应的是dragstart事件,如果有返回值那么这个值会传递到drop和dragend

useDrag({
    begin:()=>{
        dispatch({
            type:'init_drag'
        })
        
        return {
            type:'drag_id'
        }
    }
})

end函数:对应dragend事件,可以拿到drop的结果,拖拽结束,做最后的状态变更

返回值:[CollectedProps, ConnectDragSource, ConnectDragPreview]

CollectedProps:这个返回值和useDrag中的collect参数有关,我们之前没有介绍这个参数,因为传进去再返回出来好像用处不大

ConnectDragSource:这个参数是指定拖拽元素的,很重要

const ref = useRef(null)
const [,useDragRef] = useDrag()
useDragRef(ref)

// 需要拖拽的元素
return <div ref={ref}/>

ConnectDragPreview:预览用的

useDrop

accept:对应useDrag中的item.type

collect:收集属性,这里有一个额外作用是“组织冒泡”

useDrop({
    collect: (monitor: DropTargetMonitor) => ({
      canDrop: monitor.canDrop(),
      isOverCurrent: monitor.isOver({ shallow: true })
    }),
})

canDrop:是否可以放置

hover:其实是dragEnter,会反复触发,容易引发性能问题;在这里我们可以采用diff操作避免重复触发的,因为每一个dragitem都有一个唯一id,如果说hover上去的key与当前高亮的key相同那么我们直接退出,这样就减少了页面的重排重绘

drop:触发drop事件,在dragend之前

总结

本文简单介绍了一下react-dnd的使用以及在使用过程中需要组织冒泡以及防止hover反复执行的问题;如果觉得react-dnd用的不顺手可以试试其他的拖拽组件,适合项目的才是最好的