Search code examples
reactjsreact-hooksreact-beautiful-dnd

Using `useState` with Beautiful DND in React


I've been following a guide to add beautiful dnd to my react app here https://www.youtube.com/watch?v=aYZRRyukuIw&t=1s

Here is an array of exercises

const exercises = [
  {
    title: 'Abdominal Crunch',
    id: '4YRrftQysvE1Kz8XACtrq4',
    rest: ['30', '30', '30', '30', '30', '', '', '', '', ''],
    reps: ['5', '5', '5', '5', '5', '', '', '', '', ''],
    time: false
  },
  {
    title: 'Bicep curl',
    rest: ['30', '30', '30', '', '', '', '', '', '', ''],
    reps: ['5', '5', '', '5', '', '', '', '', '', ''],
    time: false
  }
];

And I'm mapping through the exercises

...

  return (
    <section>
      <div>
        <DragDropContext onDragEnd={(result) => console.log(result)}>
          <Droppable droppableId="items">
            {(provided, snapshot) => {
              return (
                <div
                  className="exercises"
                  {...provided.droppableProps}
                  ref={provided.innerRef}
                >
                  {exercises.map((exercise, index) => {
                    return (
                      <Draggable
                        key={exercise.id}
                        draggableId={exercise.id}
                        index={index}
                      >
                        {(provided, snapshot) => {
                          return (
                            <div
                              className="exercise__item"
                              {...provided.draggableProps}
                              {...provided.dragHandleProps}
                              å
                              ref={provided.innerRef}
                              style={{
                                userSelect: "none",
                                ...provided.draggableProps.style,
                              }}
                            >
                              {exercise} 
                            </div>
                          );
                        }}
                      </Draggable>
                    );
                  })}
                  {provided.placeholder}
                </div>
              );
            }}
          </Droppable>
        </DragDropContext>
      </div>
    </section>
  );
};

export default ExercisesList;

This is working perfectly but the problem I'm having is saving the state onDragEnd.

  const onDragEnd = (result) => {
     if(!result.destination) return;
   // Can I save the state in here?
  }

Using the existing state I have already configured?

  const fieldValue = props.sdk.field.getValue();
  const [exercises, setExercises] = useState(fieldValue || []);

Solution

  • You need to access the result object to receive the initial and final index of the item and reorder the array accordingly:

    const onDragEnd = (result) => {
      if(!result.destination) return;
      setExercises(prevExercises => {
        const exercises = Array.from(prevExercises); // Create a new array to not mutate the previous one
        const [removed] =  exercises.splice(result.source.index, 1); // Removes the drag item from the array by using the start index
        exercises.splice(result.destination.index, 0, removed); // Inserts the moved item at its new position using the end index
        return exercises // Returns the reordered array to the hook to be saved
      })
    }
    
    

    I updated the names, @david-riches