reactjs - 如何实现react-dnd useDragLayer?

标签 reactjs drag-and-drop react-dnd

我有一个组件当前使用 useDrag Hook 连接到 react-dnd。它运作良好,除了预览。我想实现 useDragLayer,看看它是否有助于解决我的预览问题,正如许多在线线程所建议的那样。

这是我当前的(简化的)useDrag 实现:

const [{ isDragging }, connectDragSource, connectPreview] = useDrag({
  item,
  collect: monitor => ({
    isDragging: monitor.getItem()?.index === item.index,
  })
})

return (
  <Wrapper ref={connectPreview} isDragging={isDragging}>
    <DragHandle ref={connectDragSource} />
  </Wrapper> 
)

如何在这种情况下以有助于预览的方式使用 useDragLayer?文档示例对我来说意义不大......

如何使用 useDragLayer api 连接我渲染的组件? useDragLayer 不返回拖动源和预览连接器函数(就像 useDrag 在返回数组的索引 1 和 2 上做的那样),并且它的 collect 函数不提供 DragSourceConnector实例要么。那么我调用之后的hook/返回值怎么办呢?

最佳答案

我刚刚解决了这个问题并想分享它来帮助其他人:)

您需要做几件事才能完全发挥作用。

  1. 通过添加以下 useEffect 禁用默认预览行为
import { getEmptyImage } from "react-dnd-html5-backend";

const [{ isDragging }, drag, dragPreview] = useDrag(() => ({
  type: "BOX",
  collect: (monitor) => ({
    isDragging: monitor.isDragging(),
  }),
}));

useEffect(() => {
  dragPreview(getEmptyImage(), { captureDraggingState: true });
}, []);
  1. 创建自定义默认图层

export const CustomDragLayer = (props: {}) => {
  const {
    itemType,
    isDragging,
    initialCursorOffset,
    initialFileOffset,
    currentFileOffset,
  } = useDragLayer((monitor) => ({
    item: monitor.getItem(),
    itemType: monitor.getItemType(),
    initialCursorOffset: monitor.getInitialClientOffset(),
    initialFileOffset: monitor.getInitialSourceClientOffset(),
    currentFileOffset: monitor.getSourceClientOffset(),
    isDragging: monitor.isDragging(),
  }));

  if (!isDragging) {
    return null;
  }

  return (
    <div style={layerStyles}>
      <div
        style={getItemStyles(
          initialCursorOffset,
          initialFileOffset,
          currentFileOffset
        )}
      >
        <div>Your custom drag preview component logic here</div>
      </div>
    </div>
  );
};

const layerStyles: CSSProperties = {
  position: "fixed",
  pointerEvents: "none",
  zIndex: 100,
  left: 0,
  top: 0,
  width: "100%",
  height: "100%",
  border: "10px solid red",
};

function getItemStyles(
  initialCursorOffset: XYCoord | null,
  initialOffset: XYCoord | null,
  currentOffset: XYCoord | null
) {
  if (!initialOffset || !currentOffset || !initialCursorOffset) {
    return {
      display: "none",
    };
  }

  const x = initialCursorOffset?.x + (currentOffset.x - initialOffset.x);
  const y = initialCursorOffset?.y + (currentOffset.y - initialOffset.y);
  const transform = `translate(${x}px, ${y}px)`;

  return {
    transform,
    WebkitTransform: transform,
    background: "red",
    width: "200px",
  };
}

  1. 添加 <CustomDragLayer />到顶级组件

您需要包含 ref={drag}到要拖动的组件并删除 connectPreview完全引用。

希望这对您有所帮助。

关于reactjs - 如何实现react-dnd useDragLayer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69440259/

相关文章:

reactjs - 乐观的 React Apollo ui 滞后与 React 美丽的拖放

javascript - ReactJS - 无法导入组件

javascript - React 和 d3.js,如何确保 d3 组件在 `.setState()` 上渲染

javascript - 启用/禁用可排序取决于元素组

c# - 如何为所有子控件启用拖放

reactjs - React dnd 将放置的项目的对象推送到组件的状态。

reactjs - 在 React 中,如何在所有组件中拥有一个自定义钩子(Hook)的单个实例?

javascript - for in 循环在 jsx 中得到了意外的标记

javascript - 禁用拖放动画 Chrome/Safari

reactjs - React-dnd 的 connectDragPreview() 是如何工作的?