React BeautifulDnDでReactにドラッグアンドドロップを追加する方法

ドラッグアンドドロップは、人々がページ上で物事を直感的に移動できるようにするために追加された一般的な対話手法です。これは、リストを並べ替えたり、パズルを組み立てたりすることもできます。

React Beautiful DnDを使用してReactアプリを構築するときに、そのインタラクションをどのように追加できますか?

  • ドラッグアンドドロップとは何ですか?
  • React Beautiful DnDとは何ですか?
  • 何を構築しますか?
  • ステップ0:新しいReact.jsアプリを作成する
  • ステップ1:React BeautifulDnDをインストールする
  • ステップ2:React BeautifulDnDを使用してリストをドラッグおよびドロップ可能にする
  • ステップ3:React Beautiful DnDでアイテムを並べ替えた後、リストの順序を保存する

ドラッグアンドドロップとは何ですか?

ドラッグアンドドロップは、ほとんどそのように聞こえます。これは、誰かがアイテムをクリックしてドラッグし、それを別の場所にドロップできるようにするインタラクションであり、多くの場合、アプリ内で副作用があります。

この効果は、やることリストやプロジェクト管理ダッシュボードなどのアプリケーションで非常に一般的です。このアプリケーションでは、優先順位を付けて、実行方法の順序を作成する必要があります。

ドラッグアンドドロップにはいくつかの高度なユースケースがありますが、ウォークスルーでは基本的なリスト機能に固執します。

React Beautiful DnDとは何ですか?

React Beautiful DnDは、Atlassianからアクセス可能なドラッグアンドドロップライブラリです。Atlassianを知らない場合は、Jiraの背後にあるチームです。Jiraに慣れていない場合は、おそらく現在インターネット上で最大のアジャイルツールです。

チームの目標は、強力なAPIを使用して夜間のパフォーマンスを維持することに加えて、アクセシビリティを念頭に置いたドラッグアンドドロップ機能を提供することでした。

何を構築しますか?

簡単なリストから始めて、ドラッグアンドドロップする機能を追加します。

このウォークスルーでは、リスト自体の作成に時間を費やすことはありません。使用するリストは、標準の順序なしリストを使用します(

Original text


    )およびリストアイテム(
  • )CSSを少し使用してリストを作成し、カードのように見せます。

    React Beautiful DnDを使用して、ドラッグアンドドロップでリストを再配置する機能の追加に焦点を当てます。

    ステップ0:新しいReact.jsアプリを作成する

    まず、アイテムのリストを含むシンプルなアプリが必要です。これは、既存のプロジェクトでも、Create ReactAppなどのお気に入りのフレームワークを使用した新しいプロジェクトでもかまいません。

    Create Reactアプリを使用して新しいアプリから始め、ファイナルスペースのキャラクターの簡単なリストを追加しました。

    同じ場所から始めたい場合は、そのブランチで私のデモリポジトリのクローンを作成し、私と一緒に始めることができます。

    このコマンドは、開始するために特定のブランチのクローンを作成します。

    git clone --single-branch --branch part-0-starting-point [email protected]:colbyfayock/my-final-space-characters.git 

    それ以外の場合は、通常どおりリポジトリのクローンを作成して、ブランチをチェックアウトできますpart-0-starting-point

    コードだけをフォローしたい場合は、最初にオブジェクトの配列を作成しました。

    const finalSpaceCharacters = [ { id: 'gary', name: 'Gary Goodspeed', thumb: '/images/gary.png' }, ... 

    次に、それらをループしてリストを作成します。

      {finalSpaceCharacters.map(({id, name, thumb}) => { return (
    • { name }

    • ); })}

    コミットに従ってください!

    ステップ1:React BeautifulDnDをインストールする

    最初のステップは、npmを介してライブラリをインストールすることです。

    プロジェクト内で、以下を実行します。

    yarn add react-beautiful-dnd # or npm install react-beautiful-dnd --save 

    これにより、ライブラリがプロジェクトに追加され、アプリで使用できるようになります。

    ステップ2:React BeautifulDnDを使用してリストをドラッグおよびドロップ可能にする

    ライブラリをインストールすると、リストにドラッグアンドドロップできるようになります。

    アプリにドラッグアンドドロップコンテキストを追加する

    ファイルの先頭で、次のコマンドを使用DragDropContextしてライブラリからインポートします。

    import { DragDropContext } from 'react-beautiful-dnd'; 

    DragDropContext is going to give our app the ability to use the library. It works similarly to React’s Context API, where the library can now have access to the component tree.

    Note: If you plan on adding drag and drop to more than one list, you need to make sure that your DragDropContext wraps all of those items, like at the root of your application. You can not nest DragDropContext.

    We’ll want to wrap our list with DragDropContext:

      ...

    At this point, nothing will have changed with the app and it should still load as it did before.

    Making our list a Droppable area

    Next, we want to create a Droppable area, meaning, this will allow us to provide a specific area where our items can be moved around inside.

    First, add Droppable to our import at the top of the file:

    import { DragDropContext, Droppable } from 'react-beautiful-dnd'; 

    For our purpose, we want our entire unordered list (

      ) to be our drop zone, so we’ll again want to wrap it with this component:

        {(provided) => ( 
        ...
      )}

      You’ll notice we wrapped it a bit differently this time though. First, we set a droppableId on our component. This allows the library to keep track of this specific instance between interactions.

      We’re also creating a function immediately inside of that component that passes in the provided argument.

      Note: This function can pass in two arguments including a snapshot argument, but we won’t be using it in this example.

      The provided argument include information and references to code that the library needs to work properly.

      To use it, on our list element, let’s add:

      This is going to create a reference (provided.innerRef) for the library to access the list element’s HTML element.  It also applies props to the element (provided.droppableProps) that allows the library to keep track of movements and positioning.

      Again, at this point, there won’t be any noticeable functionality.

      Making our items Draggable

      Now for the fun part!

      The final piece of making our list elements draggable and droppable is wrapping each list item with a component similar to what we just did with the entire list.

      We’ll be using the Draggable component, which again, similar to the Droppable component, will include a function where we’ll pass through props to our list item components.

      First, we need to import Draggable along with the rest of the components.

      import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; 

      Next, inside of our loop, let’s wrap the returning list item with the component and it’s top level function.

      {finalSpaceCharacters.map(({id, name, thumb}) => { return (  {(provided) => ( 
    • ...
    • )}

      Because we now have a new top level component in our loop, let’s move the key prop from the list element to Draggable:

      {finalSpaceCharacters.map(({id, name, thumb}) => { return (  {(provided) => ( 
    • We also need to set two addition props on , a draggableId and an index.

      We’ll want to add index as an argument into our map function and then include those props on our component:

      {finalSpaceCharacters.map(({id, name, thumb}, index) => { return (  

      Finally, we need to set some props on the list element itself.

      On our list element, add this ref and spread additional props from the provided argument:

       {(provided) => ( 
    • Now, if we refresh our page, and hover over our list items, we can now drag them around!

      However, you’ll notice that when you start moving an item around, the bottom of the page appears to be a little messed up. There’s some overflow issues with our list items and our footer.

      You’ll also notice that in the developer console, React Beautiful DnD is giving us a warning message that we’re missing something called a placeholder.

      Adding a placeholder from React Beautiful DnD

      Part of React Beautiful DnD’s requirements is that we additionally include a placeholder item.

      This is something that they provide out of the box, but this is used to fill up the space that the item we’re dragging previously took.

      To add that, we want to include provided.placeholder at the bottom of our Droppable top level list component, in our case at the bottom of the

        :

         {(provided) => ( 
          ... {provided.placeholder}
        )}

        And if we start dragging things around in our browser, we can see that our page flow doesn’t have issues and the content stays where it should!

        The last issue though, is when you move something around, it doesn’t stay, so how can we save the order of our items?

        Follow along with the commit!

        Step 3: Saving list order after reordering items with React Beautiful DnD

        When we move our items, they stay where they land for a split second. But after React Beautiful DnD finishes doing its work, our component tree will rerender.

        When the components rerender, our items go back to the same place that they were before, because we never saved that outside of DnD’s memory.

        To resolve this, DragDropContext takes in an onDragEnd prop that will allow us to fire a function after dragging has complete. That function passes in arguments that includes the new order of our items so that we can update our state for the next render cycle.

        Saving our list items in state

        First, let’s store our items in state so that we’ll have something to update between cycles.

        At the top of the file, add useState to the React import:

        import React, { useState } from 'react'; 

        Then, we’re going to create our state using our default list of items.

        Add the following to the top of our App component:

        const [characters, updateCharacters] = useState(finalSpaceCharacters); 

        Because we’ll be updating our new characters state to provide our list items and their order, we’ll now want to replace the array we’re mapping through to our new state:

          {characters(({id, name, thumb}, index) => {

        And if we save and refresh our page, nothing should change!

        Updating state when dragging items

        Now that we have our state, we can update that state any time our list items are dragged.

        The DragDropContext component that we added to our page takes in a prop onDragEnd. Like it sounds, that will fire a function whenever someone stops dragging an item in the list.

        Let’s add a function handleOnDragEnd as our prop:

        Next, we need that function to actually exist.

        We can define a function under our state:

        function handleOnDragEnd(result) { } 

        Our function takes an argument called result.

        If we add console.log(result) to the function and move an item in our list, we can see that it includes details about what should be the updated state after our move action.

        Particularly, we want to use the index value in both the destination and source properties, which tell us the index of the item being moved and what the new index of that item should be in the array of items.

        So using that, let’s add the following to our function:

        const items = Array.from(characters); const [reorderedItem] = items.splice(result.source.index, 1); items.splice(result.destination.index, 0, reorderedItem); updateCharacters(items); 

        Here’s what we’re doing:

        • We create a new copy of our characters array
        • We use the source.index value to find our item from our new array and remove it using the splice method
        • That result is destructured, so we end up with a new object of reorderedItem that is our dragged item
        • We then use our destination.inddex to add that item back into the array, but at it’s new location, again using splice
        • Finally, we update our characters state using the updateCharacters function

        And now after saving our function, we can move our characters around, and they save their location!

        Preventing errors from dragging out of bounds

        One issue with our implementation, is if someone doesn’t drag the item exactly within our defined containers, we get an error.

        The issue is that when we drag it outside of the defined container, we don’t have a destination.

        To avoid this, we can simply add a statement above the code that moves our item around that checks if the destination exists, and if it doesn’t, exits out of the function:

        function handleOnDragEnd(result) { if (!result.destination) return; 

        And if we reload the page and try to drag our item out again, our item snaps back to the original location without an error!

        Follow along with the commit!

        What else can we do with React Beautiful DnD?

        Custom styles when dragging and dropping

        When moving items, DnD will provide a snapshot of the given state. With this information, we can apply custom styles so that when we’re moving our items, we can show an active state for the list, the item we’re moving, or both!

        //react-beautiful-dnd.netlify.app/?path=/story/single-vertical-list--basic

        Dragging between different lists

        If you’ve used Trello before or a tool like it, you should be familiar with the concept of different columns that you can drag cards between so that you can prioritize and organize your tasks and ideas.

        This library allows you to do the same thing, providing the ability to drag and drop items from one draggable area to another.

        //react-beautiful-dnd.netlify.app/?path=/story/multiple-vertical-lists--stress-test

        Follow me for more Javascript, UX, and other interesting things!

        • ? Follow Me On Twitter
        • ? Subscribe To My Youtube
        • ✉️ Sign Up For My Newsletter
        • ? Sponsor Me