简体   繁体   中英

Adding drag`n`drop(react-dnd) to Material-UI component [TreeView]

I have a question. I created a TreeView and tried to bind the drag'n'drop, everything works, the TreeItem can be moved. BUT. If you expand any TreeItem and try to drag it, then all its child TreeItems will move with it.

How to make only one TreeItem drag'n'drop, without its child TreeItems????

My guess is I need to access the inner component of the item tree. I also don't know how to do this.

My Code:

export const PathTreeItem = (props: PathTreeItemProps) => {
  const [obj, setObj] = useState<TreeItemType[] | undefined>(undefined)
  const [isCurrentRequest, setIsCurrentRequest] = useState(false)

  const [{ isDragging }, drag] = useDrag({
    item: { type: props.obj.description || 'asd' },
    canDrag: true,
    collect: (monitor: DragSourceMonitor) => ({
      isDragging: monitor.isDragging(),
    }),
  })

  const treeItemStyle = useMemo(
    () => ({
      opacity: isDragging ? 0.4 : 1,
    }),
    [isDragging]
  )

  useEffect(() => {
    if (isCurrentRequest && props.obj.parameter_type === 'ABC') {
      APIs.get(props.obj.name)
        .then(res => {
          setObj(res.data)
        })
        .catch(err => {=
          console.error('Error ', err)
        })
    }
  }, [isCurrentRequest])

  const handleLabelCLick = useCallback(event => {
    console.log(event)
    setIsCurrentRequest(!isCurrentRequest)
  }, [])

  return (
    <TreeItem
      ref={drag}
      style={treeItemStyle}
      nodeId={props.index}
      label={props.obj.description}
      onLabelClick={handleLabelCLick}
    >
      {props.obj.parameter_type === 'ABC' ? (
        obj ? (
          obj.map((value, index) => (
            <PathTreeItem
              key={props.keyIndex * 100 + index}
              keyIndex={index}
              index={`${props.index}.${index}`}
              obj={value}
            />
          ))
        ) : (
          <div></div>
        )
      ) : null}
    </TreeItem>
  )
}

I have solved that problem by not dragging the TreeItem itself, but a custom component attached to it as its label attribute. Unfortunately, the solution currently only works in Firefox, not in Chrome or Safari:

const CustomItem = () => {
  return (
    // custom item components (Box, Typography, etc.)
  );
}

const DraggableCustomItem = () => {
  const [{ isDragging }, drag] = useDrag({
    collect: (monitor: DragSourceMonitor) => ({
      isDragging: monitor.isDragging()
    }),
    type: 'CustomItem'
  })
  
  return (
    <div ref={drag} style={{ opacity: isDragging ? 0.5 : 1}}>
      <CustomItem/>
    </div>
  )
}

const TreeViewDraggableCustomItem = () => {
  return (
    <TreeView>
      <TreeItem key    = { '1' }
                nodeId = { '1' }
                label  = { <DraggableCustomItem/> }>
    </TreeView>
  );
}

See also related SO question , example sandbox and github comment .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM