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

React问题:点击Column1旁展开面板无法显示Column3内容

React新手问题:点击按钮无法显示Column3条目

我是React新手,预期点击Column1标题旁的「open panel」按钮时,可显示Column3的条目。已使用useState进行状态管理,但功能仍无法正常运行,调试后也未解决问题。

问题代码中的核心问题

  1. 重复的Droppable ID:代码中创建了两个droppableId="column3"的组件,react-beautiful-dnd要求每个Droppable的ID必须唯一,这会导致渲染和拖拽逻辑冲突。
  2. Draggable嵌套错误:面板内的Draggable组件错误嵌套了完整的Droppable结构,还重复渲染了Column3内容,同时错误传递了provided.droppableProps(这是Droppable组件的专属props,不能用于Draggable)。
  3. 面板渲染逻辑混乱:面板的触发逻辑与重复的Droppable组件绑定,导致状态切换时无法正确渲染目标内容。
  4. 状态更新问题:跨列移动时直接修改原状态对象的数组,没有创建深拷贝,导致React无法检测到状态变化,界面不更新。

修复后的代码

import { useState } from 'react';
import './App.css';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

function App() {
  const [panelOpen, setPanelOpen] = useState(false);

  const [columns, setColumns] = useState({
    column1: { id: 'column1', items: ['Sample_Step1', 'Sample_Step2'] },
    column2: { id: 'column2', items: [] },
    column3: { id: 'column3', items: ['Sample_Step6', 'Sample_Step7'] },
  });

  const handleDragEnd = (result) => {
    const { source, destination } = result;
    if (!destination) return;

    // 同列重排逻辑
    if (source.droppableId === destination.droppableId) {
      const column = columns[source.droppableId];
      const copiedItems = [...column.items];
      const [removed] = copiedItems.splice(source.index, 1);
      copiedItems.splice(destination.index, 0, removed);

      setColumns({
        ...columns,
        [source.droppableId]: { ...column, items: copiedItems },
      });
    } else {
      // 跨列移动逻辑(修复状态更新问题)
      const sourceColumn = { ...columns[source.droppableId], items: [...columns[source.droppableId].items] };
      const destColumn = { ...columns[destination.droppableId], items: [...columns[destination.droppableId].items] };
      const [removed] = sourceColumn.items.splice(source.index, 1);
      destColumn.items.splice(destination.index, 0, removed);

      setColumns({
        ...columns,
        [source.droppableId]: sourceColumn,
        [destination.droppableId]: destColumn,
      });
    }
  };

  return (
    <div>
      <DragDropContext onDragEnd={handleDragEnd}>
        <div style={{ display: 'flex', gap: '20px', padding: '20px' }}>
          <Droppable droppableId="column1">
            {(provided) => (
              <div 
                {...provided.droppableProps} 
                ref={provided.innerRef}
                style={{ minWidth: '200px' }}
              >
                <h5>
                  column 1 header{' '}
                  <span 
                    onClick={() => setPanelOpen(!panelOpen)}
                    style={{ cursor: 'pointer', color: '#165DFF', textDecoration: 'underline', marginLeft: '8px' }}
                  >
                    open panel
                  </span>
                </h5>
                {columns.column1.items.map((item, index) => (
                  <Draggable key={item} draggableId={item} index={index}>
                    {(provided) => (
                      <div
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        ref={provided.innerRef}
                        style={{ padding: '8px', border: '1px solid #E5E6EB', borderRadius: '4px', margin: '4px 0', backgroundColor: '#FFF' }}
                      >
                        <p>{item}</p>
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>

          <Droppable droppableId="column2">
            {(provided) => (
              <div 
                {...provided.droppableProps} 
                ref={provided.innerRef}
                style={{ minWidth: '200px' }}
              >
                <h5>column 2 header</h5>
                {columns.column2.items.map((item, index) => (
                  <Draggable key={item} draggableId={item} index={index}>
                    {(provided) => (
                      <div
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        ref={provided.innerRef}
                        style={{ padding: '8px', border: '1px solid #E5E6EB', borderRadius: '4px', margin: '4px 0', backgroundColor: '#FFF' }}
                      >
                        <p>{item}</p>
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>

          <Droppable droppableId="column3">
            {(provided) => (
              <div 
                {...provided.droppableProps} 
                ref={provided.innerRef}
                style={{ minWidth: '200px' }}
              >
                <h5>column 3 header</h5>
                {columns.column3.items.map((item, index) => (
                  <Draggable key={item} draggableId={item} index={index}>
                    {(provided) => (
                      <div
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        ref={provided.innerRef}
                        style={{ padding: '8px', border: '1px solid #E5E6EB', borderRadius: '4px', margin: '4px 0', backgroundColor: '#FFF' }}
                      >
                        <p>{item}</p>
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>

          {/* 折叠面板:点击按钮后显示Column3条目 */}
          {panelOpen && (
            <div 
              className="vertical-panel" 
              style={{ 
                minWidth: '200px', 
                border: '1px solid #E5E6EB', 
                borderRadius: '4px', 
                padding: '10px', 
                marginTop: '24px',
                backgroundColor: '#F7F8FA'
              }}
            >
              <h5>column 3 面板</h5>
              {columns.column3.items.map((item, index) => (
                <Draggable key={item} draggableId={item} index={index}>
                  {(provided) => (
                    <div
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                      ref={provided.innerRef}
                      style={{ padding: '8px', border: '1px solid #E5E6EB', borderRadius: '4px', margin: '4px 0', backgroundColor: '#FFF' }}
                    >
                      <p>{item}</p>
                    </div>
                  )}
                </Draggable>
              ))}
            </div>
          )}
        </div>
      </DragDropContext>
    </div>
  );
}

export default App;

修复说明

  1. 删除重复Droppable:移除了第二个droppableId="column3"组件,确保每个拖拽容器ID唯一。
  2. 重构面板逻辑:将折叠面板独立出来,通过panelOpen状态直接控制显示/隐藏,不再嵌套错误的拖拽结构。
  3. 修复状态更新:跨列移动时对列对象和数组进行深拷贝,确保React能检测到状态变化,触发界面更新。
  4. 优化交互体验:给按钮添加了样式提示,给拖拽项增加了基础样式,提升界面可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 09:18:10