Проблема с примером React Card: карта заменяется, а не добавляется к списку карт в другом столбце

Я настойчиво работал над этой проблемой, цель которой состоит в том, чтобы перетащить карточку из «Столбца 1» и скопировать ее в другой столбец, скажем, «Столбец 2». Теперь, когда моя первая карта перетаскивается и помещается в «Столбец 2», карта соответственно добавляется в этот столбец, но когда я перетаскиваю другую карту и помещаю ее в «Столбец 2» вместо добавления, она просто заменяет существующую карту собой. Я отлаживаю состояние, но проблема все еще сохраняется. Я не понял, что я здесь делаю не так?

Вот мой код

// Card Component
function Card({ id, text, isDrag }) {
  const [, drag] = useDrag(() => ({
    type: "bp-card",
    item: () => {
      return { id,  text}
    },
    collect: monitor => ({
      isDragging: !!monitor.isDragging(),
    }),
    canDrag: () => isDrag
  }));

  return (
    <div
      className='card'
      ref = {drag}
      style = {{
        cursor: isDrag ? 'pointer' : 'no-drop'
      }}
    >
      {text}
    </div>
  )
}

// Column Component
function Column({ title, children, onCardDropped }) {
  const [, drop] = useDrop(() => ({
    accept: "bp-card",
    drop: item => {
      onCardDropped(item);
    }
  }));

  return (
    <div className = "flex-item" ref = {title === 'Column 2' ? drop : null}>
      <p>{title}</p>

      {children.length > 0 && children.map(({ id, text, isDrag }) => (
        <Card
          key = {id}
          id = {id}
          text = {text}
          isDrag = {isDrag}
        />
      ))}
    </div>
  )
}

// Main App
function App() {
  const [cards] = useState([
    { id: 1, text: 'Card 1', isDrag: true },
    { id: 2, text: 'Card 2', isDrag: true },
  ]);

  const [columns, setColumns] = useState([
    {
      id: 1,
      title: 'Column 1',
      children: cards
    },
    {
      id: 2,
      title: 'Column 2',
      children: []
    },
  ]);

  const onCardDropped = ({ id, text }) => {
    // let card = null;
    const targetColumnId = 2;

    const transformedColumns = columns.map(column => {
      if (column.id === targetColumnId) {
        return {
          ...column,
          children: [
            ...column.children,
            { id, text }
          ]
        }
      }
      return column;
    });

    setColumns(transformedColumns);
  }

  return (
    <DndProvider backend = {HTML5Backend}>
      <div className='flex-container'>
        {columns.map((column) => (
          <Column
            key = {column.id}
            title = {column.title}
            children = {column.children}
            onCardDropped = {onCardDropped}
          />
        ))}
      </div>
    </DndProvider>
  );
}

Любая помощь высоко ценится. Спасибо.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
0
22
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно учитывать предыдущее состояние, используя обратный вызов метода set state. Он начинает работать после изменения onCardDropped, как показано ниже.

  const onCardDropped = ({ id, text }) => {
    // let card = null;
    const targetColumnId = 2;

    setColumns((prevColumns) =>
      prevColumns.map((column) => {
        if (column.id === targetColumnId) {
          return {
            ...column,
            children: [...column.children, { id, text }]
          };
        }
        return column;
      })
    );
  };

Всегда полезно использовать состояние из метода обратного вызова, а не напрямую использовать объект состояния, который может быть устаревшим.

Рабочая демонстрация

Edit cool-dew-8zl3s9

@Mayur Prakash Upadhyay, посмотри!!

Amila Senadheera 07.05.2022 07:45

Да. это работает так, как ожидалось! Это было прямо здесь. Спасибо, что разобрались.

Mayur Upadhyay 07.05.2022 09:31

Другие вопросы по теме