Search code examples
reactjstypescriptdrag-and-dropreact-beautiful-dnd

React dnd broad not working on the typescript


I tried to using this react dnd on the react typescript. sample not working on the type script project , any one know how to do that correctly on the react typescript

import React, { Component } from 'react';
    import ReactDOM from 'react-dom';
    import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

    // fake data generator
    const getItems = (count, offset = 0) =>
      Array.from({ length: count }, (v, k) => k).map(k => ({
        id: `item-${k + offset}`,
        content: `Item: ${k + offset}, Random value: ${Math.round(Math.random() * 100)}`,
        color: Math.random () > 0.66 ? 'pink': Math.random() > 0.5 ? 'lightgreen' : 'beige'
      }))

    // a little function to help us with reordering the result
    const reorder = (list, startIndex, endIndex) => {
      const result = Array.from(list)
      const [removed] = result.splice(startIndex, 1)
      result.splice(endIndex, 0, removed)
      return result
    }

    /**
     * Moves an item from one list to another list.
     */
    const move = (source, destination, droppableSource, droppableDestination) => {
      const sourceClone = Array.from(source)
      const destClone = Array.from(destination)
      const [removed] = sourceClone.splice(droppableSource.index, 1)

      destClone.splice(droppableDestination.index, 0, removed)

      const result = {}
      result[droppableSource.droppableId] = sourceClone
      result[droppableDestination.droppableId] = destClone

      return result
    }

    const grid = 4

    const getItemStyle = (isDragging, draggableStyle) => ({
      // some basic styles to make the items look a bit nicer
      userSelect: 'none',
      padding: grid * 2,
      margin: `0 0 ${grid}px 0`,

      // change background colour if dragging
      background: isDragging ? 'lightgreen' : 'lightgrey',

      // styles we need to apply on draggables
      ...draggableStyle
    })

    const getListStyle = isDraggingOver => ({
      background: isDraggingOver ? 'lightblue' : '#eee',
      padding: grid,
      margin: '3px',
      width: 250
    })

    class App extends Component {
      state = {
        list1: getItems(5,1),
        list2: getItems(4, 6),
        list3: getItems(6, 10)
      }

      /**
       * A semi-generic way to handle multiple lists. Matches
       * the IDs of the droppable container to the names of the
       * source arrays stored in the state.
       */
      droppableIds = {
        droppable1: 'list1',
        droppable2: 'list2',
        droppable3: 'list3'
      }

      getList = id => this.state[this.droppableIds[id]]

      onDragEnd = result => {
        const { source, destination } = result

        // dropped outside the list
        if (!destination) { return }

        if (source.droppableId === destination.droppableId) {
          const items = reorder(
            this.getList(source.droppableId),
            source.index,
            destination.index
          )

          let copiedState = Object.assign({}, this.state)

          if (source.droppableId === 'droppable1') {
            copiedState.list1 = items
          } else if (source.droppableId === 'droppable2') {
            copiedState.list2 = items
          } else if (source.droppableId === 'droppable3') {
            copiedState.list3 = items
          }

          this.setState(copiedState)
        } else {
          const result = move(
            this.getList(source.droppableId),
            this.getList(destination.droppableId),
            source,
            destination
          )

          console.warn('result', result)
          this.setState({
            list1: result.droppable1 ? result.droppable1 : this.state.list1,
            list2: result.droppable2 ? result.droppable2 : this.state.list2,
            list3: result.droppable3 ? result.droppable3 : this.state.list3
          })
        }
      }

      // Normally you would want to split things out into separate components.
      // But in this example everything is just done in one place for simplicity
      render() {
        const lists = [
          {
            droppableId: 'droppable1',
            listId: 'list1',
            title: 'List A'
          },
          {
            droppableId: 'droppable2',
            listId: 'list2',
            title: 'List B'
          },
          {
            droppableId: 'droppable3',
            listId: 'list3',
            title: 'List C'
          },
        ]
        return (
          <div style={{ display: 'flex' }}>
            <DragDropContext onDragEnd={this.onDragEnd}>

              {lists.map((list, listIndex) =>
                <Droppable key={'list-droppable-' + listIndex} droppableId={list.droppableId}>
                  {(provided, snapshot) => (
                    <div
                      ref={provided.innerRef}
                      style={getListStyle(snapshot.isDraggingOver)}>
                      <h4>
                        {list.title}
                      </h4>
                      {this.state[list.listId] && this.state[list.listId].map((item, index) => (
                        <Draggable
                          key={item.id}
                          draggableId={item.id}
                          index={index}>
                          {(provided, snapshot) => (
                            <div
                              ref={provided.innerRef}
                              { ...provided.draggableProps }
                              { ...provided.dragHandleProps }
                              style={getItemStyle(
                                snapshot.isDragging,
                                provided.draggableProps.style
                              )}>
                              <div style={{ background: item.color }}>
                                {item.content}
                              </div>
                            </div>
                          )}
                        </Draggable>
                      ))}
                      {provided.placeholder}
                    </div>
                  )}
                </Droppable>
              )}
            </DragDropContext>
          </div>
        )
      }
    }

    // Put the things into the DOM!
    ReactDOM.render(<App />, document.getElementById('root'));

Solution

  • Try something like this.

    import React, { Component } from "react";
    import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
    
    // fake data generator
    const getItems = (count: number, offset: number): object =>
      Array.from({ length: count }, (v, k): number => k).map(
        (k: number): {} => ({
          id: `item-${k + offset}`,
          content: `Item: ${k + offset}, Random value: ${Math.round(
            Math.random() * 100
          )}`,
          color:
            Math.random() > 0.66
              ? "pink"
              : Math.random() > 0.5
              ? "lightgreen"
              : "beige"
        })
      );
    
    // a little function to help us with reordering the result
    const reorder = (list: [], startIndex: number, endIndex: number): object => {
      const result = Array.from(list);
      const [removed] = result.splice(startIndex, 1);
      result.splice(endIndex, 0, removed);
      return result;
    };
    
    /**
     * Moves an item from one list to another list.
     */
    const move = (
      source: any,
      destination: any,
      droppableSource: any,
      droppableDestination: any
    ): {} => {
      const sourceClone = Array.from(source);
      const destClone = Array.from(destination);
      const [removed] = sourceClone.splice(droppableSource.index, 1);
    
      destClone.splice(droppableDestination.index, 0, removed);
    
      let result: any = {};
      result[droppableSource.droppableId] = sourceClone;
      result[droppableDestination.droppableId] = destClone;
    
      return result;
    };
    
    const grid = 4;
    
    const getItemStyle = (isDragging: boolean, draggableStyle: any): object => ({
      // some basic styles to make the items look a bit nicer
      userSelect: "none",
      padding: grid * 2,
      margin: `0 0 ${grid}px 0`,
    
      // change background colour if dragging
      background: isDragging ? "lightgreen" : "lightgrey",
    
      // styles we need to apply on draggables
      ...draggableStyle
    });
    
    const getListStyle = (isDraggingOver: boolean): object => ({
      background: isDraggingOver ? "lightblue" : "#eee",
      padding: grid,
      margin: "3px",
      width: 250
    });
    
    interface State {
      list1: object;
      list2: object;
      list3: object;
    }
    
    class App extends Component<State> {
      state: State = {
        list1: getItems(5, 1),
        list2: getItems(4, 6),
        list3: getItems(6, 10)
      };
    
      /**
       * A semi-generic way to handle multiple lists. Matches
       * the IDs of the droppable container to the names of the
       * source arrays stored in the state.
       */
      droppableIds = {
        droppable1: "list1",
        droppable2: "list2",
        droppable3: "list3"
      };
    
      getList = (id: string): any => this.state[this.droppableIds[id]];
    
      onDragEnd = (result: any) => {
        const { source, destination } = result;
    
        // dropped outside the list
        if (!destination) {
          return;
        }
    
        if (source.droppableId === destination.droppableId) {
          const items: object = reorder(
            this.getList(source.droppableId),
            source.index,
            destination.index
          );
    
          let copiedState: any = Object.assign({}, this.state);
    
          if (source.droppableId === "droppable1") {
            copiedState.list1 = items;
          } else if (source.droppableId === "droppable2") {
            copiedState.list2 = items;
          } else if (source.droppableId === "droppable3") {
            copiedState.list3 = items;
          }
    
          this.setState(copiedState);
        } else {
          const result: any = move(
            this.getList(source.droppableId),
            this.getList(destination.droppableId),
            source,
            destination
          );
    
          this.setState({
            list1: result.droppable1 ? result.droppable1 : this.state.list1,
            list2: result.droppable2 ? result.droppable2 : this.state.list2,
            list3: result.droppable3 ? result.droppable3 : this.state.list3
          });
        }
      };
      render() {
        const lists = [
          {
            droppableId: "droppable1",
            listId: "list1",
            title: "List A"
          },
          {
            droppableId: "droppable2",
            listId: "list2",
            title: "List B"
          },
          {
            droppableId: "droppable3",
            listId: "list3",
            title: "List C"
          }
        ];
        return (
          <div style={{ display: "flex" }}>
            <DragDropContext onDragEnd={this.onDragEnd}>
              {lists.map((list, listIndex) => (
                <Droppable
                  key={"list-droppable-" + listIndex}
                  droppableId={list.droppableId}
                >
                  {(provided: any, snapshot: any) => (
                    <div
                      ref={provided.innerRef}
                      style={getListStyle(snapshot.isDraggingOver)}
                    >
                      <h4>{list.title}</h4>
                      {this.state[list.listId] &&
                        this.state[list.listId].map((item: any, index: number) => (
                          <Draggable
                            key={item.id}
                            draggableId={item.id}
                            index={index}
                          >
                            {(provided: any, snapshot: any) => (
                              <div
                                ref={provided.innerRef}
                                {...provided.draggableProps}
                                {...provided.dragHandleProps}
                                style={getItemStyle(
                                  snapshot.isDragging,
                                  provided.draggableProps.style
                                )}
                              >
                                <div style={{ background: item.color }}>
                                  {item.content}
                                </div>
                              </div>
                            )}
                          </Draggable>
                        ))}
                      {provided.placeholder}
                    </div>
                  )}
                </Droppable>
              ))}
            </DragDropContext>
          </div>
        );
      }
    }
    
    export default App;
    

    And here is a working example codesandox