0

React Beautiful DND - Ошибка "Невозможно найти перетаскиваемый элемент с id: 1"

18

Вопрос на StackOverflow: Ошибка "Unable to find draggable with id: X" при многократном перетаскивании в React

В приведенном ниже коде интерфейс отображает два компонента "Column", и каждая колонка содержит два перетаскиваемых элемента, называемых "Tasks". Когда пользователь перетаскивает "Task" между колонками, код работает, но не всегда. При непрерывном перетаскивании элементов в какой-то момент перетаскивание останавливается, и пользователь получает ошибку:

Unable to find draggable with id: X

Я не понимаю, почему это происходит и как это исправить.

Примечание: Я предполагаю, что библиотека требует, чтобы при перетаскивании элементов вы перерасставляли и обновляли своё состояние в функции onDragEnd.

Вот мой код:

app.js

import React, { useState } from 'react';
import { DragDropContext } from 'react-beautiful-dnd';
import helper from './helper_functions';

import Column from './Components/Column';

function App() {
  let initialState = [
    {
      groupName: "Today",
      tasks: [
        { id: "1", title: "Test-1" },
        { id: "2", title: "Test-2" }
      ]
    },
    {
      groupName: "Tomorrow",
      tasks: [
        { id: "3", title: "Test-3" },
        { id: "4", title: "Test-4" }
      ]
    },
  ];

  const [taskList, setTasks] = useState(initialState);

  function onDragEnd(val) {
    let result = helper.reorder(val.source, val.destination, taskList);
    setTasks(result);
  }

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Column droppableId="Today" list={taskList[0].tasks} type="TASK" />
      <Column droppableId="Tomorrow" list={taskList[1].tasks} type="TASK" />
      <div>context hello world</div>
    </DragDropContext>
  );
}

export default App;

src/helper_functions

export default {
  reorder: function(source, destination, taskDataArr) {
    let taskData = [...taskDataArr];

    let sourceGroupIndex = taskData.findIndex(val => val.groupName === source.droppableId);
    let draggedTask = taskData[sourceGroupIndex].tasks[source.index];

    let sourceListCopyWithElementRemoved = taskData[sourceGroupIndex].tasks.filter((_, index) => index !== source.index);

    let destinationGroupIndex = taskData.findIndex(val => val.groupName === destination.droppableId);
    
    taskData[destinationGroupIndex].tasks.splice(destination.index, 0, draggedTask);
    taskData[sourceGroupIndex].tasks = sourceListCopyWithElementRemoved;

    return taskData;
  }
}

src/Components/Column

import React from 'react';
import { Droppable } from 'react-beautiful-dnd';
import Task from "../../Components/Task";

function Column(props) {
  const { droppableId, list, type } = props;

  let style = {
    backgroundColor: "orange",
    height: "300px",
    width: "400px",
    margin: "100px"
  };

  return (
    <Droppable droppableId={droppableId} type={type}>
      {provided => (
        <div {...provided.droppableProps} ref={provided.innerRef} style={style}>
          <h2>{droppableId}</h2>
          {list.map((val, index) => {
            return <Task id={val.id} key={index} index={index} title={val.title} />;
          })}
          {provided.placeholder}
        </div>
      )}
    </Droppable>
  );
}

export default Column;

src/Components/Task

import React from 'react';
import { Draggable } from 'react-beautiful-dnd';

function Task(props) {
  const { id, index, title } = props;
  let style = {
    backgroundColor: "red",
  };

  return (
    <Draggable draggableId={id} index={index} type="TASK">
      {(provided) => (
        <div
          ref={provided.innerRef}
          {...provided.draggableProps}
          {...provided.dragHandleProps}
        >
          <h4 style={style}>{title}</h4>
        </div>
      )}
    </Draggable>
  );
}

export default Task;

Можно ли узнать, что вызывает эту проблему и как её решить?

5 ответ(ов)

1

Если вы получаете следующую ошибку в React 18:

Unable to find draggable with id:

Попробуйте удалить StrictMode из вашего кода.

В некоторых случаях использование StrictMode может вызывать проблемы с библиотеками, которые не полностью поддерживают его или работают некорректно в этом режиме. Убедитесь, что вы протестировали ваше приложение после отключения StrictMode, чтобы подтвердить, что это решает проблему. Однако не забывайте, что StrictMode предназначен для выявления потенциальных проблем и улучшения качества кода, поэтому стоит также рассмотреть возможность обновления используемых библиотек для обеспечения совместимости с StrictMode.

0

В данном случае не для этого, но для всех - проверьте provided.draggableProps, а не provided.dropableProps.

<Draggable draggableId={id} index={index} type="TASK">
  {(provided) => (
    <div
      ref={provided.innerRef}
      {...provided.draggableProps}
      {...provided.dragHandleProps}
    >
      <h4 style={style}>{title}</h4>
    </div>
  )}
</Draggable>

React Beautiful DnD (RBD) пытается найти узел по provided.draggableProps. Если эти свойства отсутствуют, вы получите ошибку: Unable to find draggable with id: X. Убедитесь, что вы правильно используете provided.draggableProps для обработки перетаскивания.

0

У меня была похожая проблема, когда я перебирал несколько перетаскиваемых элементов и забыл указать свойство key. Добавление key к компоненту Draggable помогло решить проблему:

{tasks.map((t, index) => (
  <Draggable
    draggableId={t._id}
    index={index}
    key={t._id} >
    ....
  </Draggable>
))}

Не забывайте указывать уникальный key для каждого элемента в списке, чтобы React мог корректно управлять изменениями и оптимизировать рендеринг!

0

Библиотека больше не поддерживается. Я перешел на форк:

https://github.com/hello-pangea/dnd

И все проблемы были решены.

0

Если вы ищете решение, которое:

  • Не требует отключения Strict Mode
  • Не замены всей библиотеки react-beautiful-dnd

1. Создайте компонент StrictModeDroppable в вашем проекте:

import { useEffect, useState } from "react";
import { Droppable, DroppableProps } from "react-beautiful-dnd";

export const StrictModeDroppable = ({ children, ...props }: DroppableProps) => {
  const [enabled, setEnabled] = useState(false);

  useEffect(() => {
    const animation = requestAnimationFrame(() => setEnabled(true));

    return () => {
      cancelAnimationFrame(animation);
      setEnabled(false);
    };
  }, []);

  if (!enabled) {
    return null;
  }

  return <Droppable {...props}>{children}</Droppable>;
};

2. Затем замените компоненты <Droppable> в вашем проекте на <StrictModeDroppable>.

Это должно сработать!


Источник: GitHub Issue

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь