Reorder a List with react-beautiful-dnd

Alex Reardon
InstructorAlex Reardon
Share this video with your friends

Social Share Links

Send Tweet

In this lesson, we will add react-beautiful-dnd to our project to enable reordering of our tasks.

In our lesson, we use a styled-components innerRef callback to get the DOM ref for our styled component.

If you have not used ref's in React before I recommend you check out:

A small cheatsheet about refs:

  • On a React Element such as <div> the ref callback returns a DOM node
  • On a React Component such as <Person> the ref callback returns the instance of the component - which is not what react-beautiful-dnd needs
  • It is a common practice to create your own innerRef callback for your components to return the underlying DOM reference of the component

Instructor: [00:00] We are now going to add the ability to reorder the tasks in our list using React-beautiful-dnd. Let's add React-beautiful-dnd as a dependency to our project. OK, great.

[00:20] Before going any further, let's take a visual look at the components that make up React-beautiful-dnd. React-beautiful-dnd is made up of three different components. The first is the DragDropContext. The DragDropContext is a component, that we use to wrap the part of our application, that we want to have drag and drop enable form.

[00:43] A droppable creates a region which can be dropped on to. They also contain draggables. A draggable is a component that can be dragged around and dropped into droppables. In order to enable drag and drop for our column, we're going to wrap it in a DragDropContext component.

[01:02] First, we'll import DragDropContext from React-beautiful-dnd. Then, I'm going to wrap our columns inside of a DragDropContext. A DragDropContext has three call backs. onDragStart, which is called when the drag starts. onDragUpdate is called when something changes during a drag, such as an item is moved into a new position, and onDragEnd, which is called at the end of a drag.

[01:43] The only required call back for a DragDropContext is onDragEnd. It is your responsibility of your onDragEnd function to synchronously update your state to reflect the drag and drop result. We will leave this function blank for now and come back to it soon.

[02:08] We'll now enhance our column component. We are going to import the droppable component from React-beautiful-dnd. We're then going to wrap our task list component inside of the droppable. A droppable has one required prop, a droppable ID.

[02:30] This ID needs to be unique within the DragDropContext. We're going to use the column ID. You'll see that we're getting an error in our application saying, "Children is not a function." A droppable utilizes the render props pattern and expects its child to be a function that returns a React component.

[02:58] One reason the render props pattern is used, is so that React-beautiful-dnd does not need to create any DOM nodes for you. You create your components that where you want to. React-beautiful-dnd latches into your existing structure.

[03:15] The first argument to this function is called provided. Provided is an object that serves a few important purposes. A provided object has a property for droppableProps. These are props that need to be applied to the component that you want to designate as your droppable.

[03:39] We explicitly call out what all of these props are in our documentation. You can apply each one of these individually if you want, and you are even welcome to monkey patch them. However, we won't be going into that topic here.

[03:53] Generally, you'll be able to just spread the provided.droppableProps object directly on to your component. The provided object has a property called innerRef, which is a function used to supply with DOM node of your component to React-beautiful-dnd.

[04:13] A styled component has a call back prop named innerRef, which returns the DOM node of the component. We can assign the provided.innerRef function to this prop. The last thing we'll need to do for a droppable is to insert a place holder.

[04:36] A place holder is a React element that is used to increase the available space in a droppable during a drag when it's needed. The place holder needs to be added as a child of the component that you designate as the droppable. Our droppable is now set up.

[04:57] We're going to move to our task component and make it draggable. We're going to import the draggable component from React-beautiful-dnd. Now, I'm going to wrap our container component inside of a draggable component.

[05:13] A draggable has two required props. Firstly, a draggable ID, which will assign to the task ID. Secondly, it requires an index. We're currently not passing an index to our task component. Let's go back to our column component and do that.

[05:41] Our column component is currently mapping over the task's prop and returning a task component. The second argument to a map function is the index of the item in the array. We can simply pass this index on to our task component. If we can now go back to task, we still have a problem.

[06:12] As with droppable, a draggable expects its child to be a function. The first argument to this function is a provided object, which works in a very similar way to the droppable provided object we have previously seen.

[06:32] The provided object has a property called draggableProps. These props need to be applied to the component that we want to move around in response to a user input. The provided object also has another property called dragHandleProps. These are the props that need to be applied to the part of the component that we want to use to be able to control the entire component.

[07:01] You can use this to drag a large item by just a small part of it. For our application, we want the whole task to be draggable. We're going to apply these props to the same element. As with our droppable, we also need to provide a ref for our draggable.

[07:17] Now, let's take a look at our application. We can now drag items around without mouse and without keyboard, which is pretty great. What we can see that when we are dragging an item, we can see through that item when we were dragging in, which doesn't look very great.

[07:38] Let's go back to our task. Just add a background color. Just white will be fine. When the item moves, we don't see through it. Let me go. We now have a really nice looking reordering experience.

[07:57] You might have noticed that when I drop, that reorder is not preserved. In order to preserve that reorder, we need to implement our reordering logic inside of your onDragEnd call back.