首页 > 解决方案 > 使用 react-dnd beautiful 如何将新项目插入数组,或者它不起作用?

问题描述

在我的项目中,我试图将我的信息更改为 react-dnd 漂亮的拖放。

但是当我改变它时,拖放不适用于插入到数组中的新项目。

我如何使它在这个例子中仍然有效?

代码沙箱: https ://codesandbox.io/s/react-drag-and-drop-react-beautiful-dnd-forked-oo8nd?file=/src/index.js:0-5732

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

// fake data generator
const getItems = (count, offset = 0) =>
  Array.from({ length: count }, (v, k) => k).map((k) => ({
    id: `item-${k + offset}-${new Date().getTime()}`,
    content: `item ${k + offset}`
  }));

const reorder = (list, startIndex, endIndex) => {
  const result = Array.from(list);
  const [removed] = result.splice(startIndex, 1);
  result.splice(endIndex, 0, removed);

  return result;
};

/**
 * Moves an item from one list to another list.
 */
const move = (source, destination, droppableSource, droppableDestination) => {
  const sourceClone = Array.from(source);
  const destClone = Array.from(destination);
  const [removed] = sourceClone.splice(droppableSource.index, 1);

  destClone.splice(droppableDestination.index, 0, removed);

  const result = {};
  result[droppableSource.droppableId] = sourceClone;
  result[droppableDestination.droppableId] = destClone;

  return result;
};
const grid = 8;

const getItemStyle = (isDragging, draggableStyle) => ({
  // some basic styles to make the items look a bit nicer
  userSelect: "none",
  padding: grid * 2,
  margin: `0 0 ${grid}px 0`,

  // change background colour if dragging
  background: isDragging ? "lightgreen" : "grey",

  // styles we need to apply on draggables
  ...draggableStyle
});
const getListStyle = (isDraggingOver) => ({
  background: isDraggingOver ? "lightblue" : "lightgrey",
  padding: grid,
  width: 250
});

function QuoteApp() {
  const [state, setState] = useState([getItems(10), getItems(5, 10)]);

  function onDragEnd(result) {
    const { source, destination } = result;

    // dropped outside the list
    if (!destination) {
      return;
    }
    const sInd = +source.droppableId;
    const dInd = +destination.droppableId;

    if (sInd === dInd) {
      const items = reorder(state[sInd], source.index, destination.index);
      const newState = [...state];
      newState[sInd] = items;
      setState(newState);
    } else {
      const result = move(state[sInd], state[dInd], source, destination);
      const newState = [...state];
      newState[sInd] = result[sInd];
      newState[dInd] = result[dInd];

      setState(newState.filter((group) => group.length));
    }
  }

  return (
    <div>
      <button
        type="button"
        onClick={() => {
          setState([...state, []]);
        }}
      >
        Add new group
      </button>
      <button
        type="button"
        onClick={() => {
          setState([...state, getItems(1)]);
        }}
      >
        Add new item
      </button>
      <div style={{ display: "flex" }}>
        <DragDropContext onDragEnd={onDragEnd}>
          {state.map((el, ind) => (
            <Droppable key={ind} droppableId={`${ind}`}>
              {(provided, snapshot) => (
                <div
                  ref={provided.innerRef}
                  style={getListStyle(snapshot.isDraggingOver)}
                  {...provided.droppableProps}
                >
                  {el.map((item, index) => (
                    <Draggable
                      key={item.id}
                      draggableId={item.id}
                      index={index}
                    >
                      {(provided, snapshot) => (
                        <div
                          ref={provided.innerRef}
                          {...provided.draggableProps}
                          {...provided.dragHandleProps}
                          style={getItemStyle(
                            snapshot.isDragging,
                            provided.draggableProps.style
                          )}
                        >
                          <div
                            style={{
                              display: "flex",
                              justifyContent: "space-around"
                            }}
                          >
                            ind:{ind} , index{index} ,{item.content}
                            <button
                              type="button"
                              onClick={() => {
                                const newState = [...state];
                                newState[ind].splice(index, 1);
                                setState(
                                  newState.filter((group) => group.length)
                                );
                              }}
                            >
                              delete
                            </button>
                            <button
                              type="button"
                              onClick={() => {
                                const newState = [...state];
                                newState[ind].splice(
                                  index,
                                  0,
                                  getItems(1, index)
                                );
                                setState(
                                  newState.filter((group) => group.length)
                                );
                              }}
                            >
                              add s/o
                            </button>
                          </div>
                        </div>
                      )}
                    </Draggable>
                  ))}
                  {provided.placeholder}
                </div>
              )}
            </Droppable>
          ))}
        </DragDropContext>
      </div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<QuoteApp />, rootElement);

具体变化是“add s/o”按钮

感谢您的时间

标签: arraysreactjsdrag-and-drop

解决方案


问题

当您插入/添加一个“s/o”(对不起,不确定那是什么)时,您拼接的返回值getItems是一个数组,但您的主要状态形状是一个对象数组。

const getItems = (count, offset = 0) =>
  Array.from({ length: count }, (v, k) => k).map((k) => ({
    id: `item-${k + offset}-${new Date().getTime()}`,
    content: `item ${k + offset}`
  }));

...

<button
  type="button"
  onClick={() => {
    const newState = [...state];
    newState[ind].splice(
      index,
      0,
      getItems(1, index) // <-- inserts array!!
      );
    setState(
      newState.filter((group) => group.length)
    );
  }}
>
  add s/o
</button>

您插入了一个数组而不是对象。

{newState: Array(2)}
  newState: Array(2)
    0: Array(11)
      0: Array(1) // <-- inserted array
        0: Object // <-- object you want inserted
          id: "item-0-1609711045911"
          content: "item 0"
      1: Object
        id: "item-0-1609711042837"
        content: "item 0"
      2: Object
      3: Object
      4: Object
      5: Object
      6: Object
      7: Object
      8: Object
      9: Object
      10: Object
    1: Array(5)

解决方案

似乎一个相当简单的解决方案是getItems在拼接新的“s/o”时弹出单个插入的对象。

<button
  type="button"
  onClick={() => {
    const newState = [...state];
    newState[ind].splice(
      index,
      0,
      getItems(1, index).pop(), // <-- pop value from array
      );
    setState(
      newState.filter((group) => group.length)
    );
  }}
>
  add s/o
</button>

编辑 using-react-dnd-beautiful-how-do-i-insert-new-item-into-the-array-or-does-it-no


推荐阅读