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

Next.js 12.3.1中react-beautiful-dnd 13.1.1无法拖拽求助

问题:Next.js 12.3.1 中 react-beautiful-dnd 无法拖拽,无抓取光标

使用Next.js 12.3.1开发Web应用,借助react-beautiful-dnd 13.1.1实现简单垂直可拖拽列表,但所有项目都无法拖拽,鼠标悬停仅显示普通指针而非抓取光标,已尝试在_document.js中调用resetServerContext但无效果,项目编译无报错。

代码如下:

import React, { useState } from "react";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";

export default function BigOlList() {

const defaultList = ["A", "B", "C", "D", "E"];
// React state to track order of items
const [itemList, setItemList] = useState(defaultList);

// Function to update list on drop
const handleDrop = (droppedItem) => {
  // Ignore drop outside droppable container
  if (!droppedItem.destination) return;
  var updatedList = [...itemList];
  // Remove dragged item
  const [reorderedItem] = updatedList.splice(droppedItem.source.index, 1);
  // Add dropped item
  updatedList.splice(droppedItem.destination.index, 0, reorderedItem);
  // Update State
  setItemList(updatedList);
};

return (
  <div className="App">
    <DragDropContext onDragEnd={handleDrop}>
        <Droppable droppableId="list-container">
            {(provided) => (
                <div className="list-container" {...provided.droppableProps} ref={provided.innerRef}>
                    {itemList.map((item, index) => (
                        <Draggable key={item} draggableId={item} index={index}>
                            {(provided) => (
                                <div className="item-container"
                                {...provided.dragHandleProps}
                                {...provided.draggableProps}
                                ref={provided.innerRef}
                                >
                                    {item}
                                </div>
                            )}
                        </Draggable>
                    ))}
                    {provided.placeholder}
                </div>
            )}
        </Droppable>
        </DragDropContext>
  </div>
);
}

解决方案

1. 解决Next.js SSR的Hydration不匹配问题

react-beautiful-dnd依赖DOM测量,SSR环境下会导致客户端与服务端渲染结果不一致,仅在_document.js调用resetServerContext不够,需确保拖拽组件仅在客户端渲染:

方式一:用Next.js dynamic导入禁用SSR

import dynamic from 'next/dynamic';

// 动态导入拖拽组件并禁用服务端渲染
const DragDropContext = dynamic(
  () => import('react-beautiful-dnd').then(mod => mod.DragDropContext),
  { ssr: false }
);
const Droppable = dynamic(
  () => import('react-beautiful-dnd').then(mod => mod.Droppable),
  { ssr: false }
);
const Draggable = dynamic(
  () => import('react-beautiful-dnd').then(mod => mod.Draggable),
  { ssr: false }
);

方式二:组件内用状态控制客户端渲染时机

import React, { useState, useEffect } from "react";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";

export default function BigOlList() {
  const [isClient, setIsClient] = useState(false);
  const defaultList = ["A", "B", "C", "D", "E"];
  const [itemList, setItemList] = useState(defaultList);

  useEffect(() => {
    // 客户端挂载后标记为已就绪
    setIsClient(true);
  }, []);

  const handleDrop = (droppedItem) => {
    if (!droppedItem.destination) return;
    const updatedList = [...itemList];
    const [reorderedItem] = updatedList.splice(droppedItem.source.index, 1);
    updatedList.splice(droppedItem.destination.index, 0, reorderedItem);
    setItemList(updatedList);
  };

  // 客户端未就绪前不渲染拖拽组件
  if (!isClient) return null;

  return (
    <div className="App">
      <DragDropContext onDragEnd={handleDrop}>
        <Droppable droppableId="list-container">
          {(provided) => (
            <div className="list-container" {...provided.droppableProps} ref={provided.innerRef}>
              {itemList.map((item, index) => (
                <Draggable key={item} draggableId={item} index={index}>
                  {(provided) => (
                    <div className="item-container"
                      {...provided.draggableProps}
                      ref={provided.innerRef}
                    >
                      {/* 单独设置拖拽手柄,明确触发区域 */}
                      <div {...provided.dragHandleProps} className="drag-handle">☰</div>
                      {item}
                    </div>
                  )}
                </Draggable>
              ))}
              {provided.placeholder}
            </div>
          )}
        </Droppable>
      </DragDropContext>
    </div>
  );
}

2. 调整Props顺序与拖拽触发区域

  • 确保draggableProps先于dragHandleProps传递,避免props覆盖
  • 单独设置拖拽手柄(dragHandleProps),不要直接绑定在整个item容器上,明确拖拽触发区域
  • 添加基础样式确保光标显示:
.item-container {
  padding: 8px 12px;
  margin: 4px 0;
  border: 1px solid #eee;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.drag-handle {
  cursor: grab; /* 设置抓取光标 */
  user-select: none; /* 避免拖拽时选中文本 */
}

.drag-handle:active {
  cursor: grabbing; /* 拖拽中的光标样式 */
}

3. 验证resetServerContext的正确调用

在_document.js中确保服务端渲染完成后重置上下文:

import Document, { Html, Head, Main, NextScript } from 'next/document';
import { resetServerContext } from 'react-beautiful-dnd';

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    resetServerContext(); // 服务端渲染后重置上下文
    return initialProps;
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

内容的提问来源于stack exchange,提问作者Gabriel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 12:40:50