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

React中拖拽功能仅对最后添加的Button生效,问题出在哪?

问题描述

我在React组件中实现拖拽功能时遇到了问题,希望能在应用中拖拽不同的按钮。为此我创建了如下Hook:

const [{isDragging}, drag] = useDrag(() => ({
    type: 'button',
    collect: monitor => ({
      isDragging: !!monitor.isDragging(),
    }),
  }))

之后在返回结构中,我将其作为ref使用:

{articleList.map((item, idx) => {
        return(
          <Accordion expanded={isElementExpanded(item.id)} onToggle={handleToggle2(item.id)} id={item.id} size="S">
            ...
                    {item.Blocks.map((block, index) => {
                      return(
...
                          <Button id={'button-'+index} ref={drag} ...></Button>...

问题在于只有最后添加的一个Button可拖拽,其他按钮的draggable属性均为"false"。奇怪的是我给所有Button都设置了ref={drag}。请问我的错误出在哪里?

问题原因与解决方案

核心问题

你只创建了一个useDrag实例,但把它的drag ref绑定到了多个按钮上。React的ref本质是一个引用,当你在循环中重复赋值同一个ref时,它最终只会指向最后一个被渲染的元素,这就导致只有最后一个按钮能获得拖拽能力。

解决方法

为每个按钮单独创建useDrag实例,最直接的方式是把可拖拽按钮封装成独立组件,在组件内部调用useDrag钩子:

// 封装可拖拽按钮组件
const DraggableButton = (props) => {
  const [{ isDragging }, drag] = useDrag(() => ({
    type: 'button',
    collect: monitor => ({
      isDragging: !!monitor.isDragging(),
    }),
  }));
  
  return (
    <Button 
      {...props} 
      ref={drag} 
      style={{ opacity: isDragging ? 0.5 : 1 }} // 可选:添加拖拽时的视觉反馈
    />
  );
};

之后在循环中使用这个封装好的组件即可:

{articleList.map((item, idx) => {
  return(
    <Accordion expanded={isElementExpanded(item.id)} onToggle={handleToggle2(item.id)} id={item.id} size="S">
      ...
              {item.Blocks.map((block, index) => {
                return(
...
                    <DraggableButton id={'button-'+index} ...></DraggableButton>...

原理说明

每个DraggableButton组件都会独立调用useDrag,生成专属的drag ref和拖拽状态,不会出现多个元素共用同一个ref导致的覆盖问题,这样所有按钮都能拥有独立的拖拽能力。

内容的提问来源于stack exchange,提问作者Dr. Sven Alisch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 16:51:07