DDavis25
DDavis25

Reputation: 1319

List items not staying in place using react-beautiful-dnd

I'm using react-beautiful-dnd and copied the code from the tutorial to build a draggable list. It worked and looked like this:

enter image description here

And here's the code that built this: https://github.com/DDavis1025/react-beautiful-dnd

However now I'm trying to implement my own list which is a playlist that uses the input to add songs from the user's computer to the list:

enter image description here

It's partially working but I'm not able to drag the list item in place (It always goes back to the same order). Here is the code that I changed:

column-test.jsx

export default class ColumnTest extends React.Component {
constructor(props) {
    super(props);

    this.handleClick = this.handleClick.bind(this);

    this.inputRef = React.createRef();

    this.state = {
      files: [],
      audio: '',
    };

  }



handleClick = event => {

  // Helper code to read file and return promise
  const readFile = (file) => {

    const fileList = [];

    const fileReader = new FileReader();

    // create the promise and return it
    return new Promise((resolve, reject) => {

      // if file reader has an error, report it
      fileReader.onerror = (error) => {
        reject({ error })
      }

      // if success, resolve the promise
      fileReader.onload = (e) => {
        resolve({
          name: file.name,
          link: e.target.result
        })
      }

      // start reading the file
      fileReader.readAsDataURL(file);

    })
  }


  // create all the file reader promises
  // create an array from the files list and use map to generate
  // an array of promises
  const allReaders = Array.from(event.target.files).map(readFile)

  // Now handle the array of promises we just created
  Promise.all(allReaders)
    .then(fileList => {
      console.log(fileList)
      // set the state that we have all the files
      this.setState({ files: fileList });
    })
    .catch(error => { 
       console.error(error)
    });


}





  render() {
      return (
      <div className="downloadMusic">
      <div className="input">
        <input
          onChange={this.handleClick}
          id="upload-file"
          className="inputName"
          type="file"
          multiple
          ref={this.inputRef}
        />
        </div>
        <div className="audio-player">

       <audio
       controls
       autoPlay
       src={this.state.audio}
        />
         </div>



        <Container>
           <Title>{this.props.column.title}</Title>
           <Droppable droppableId={this.props.column.id}>
            {provided => (
             <TaskList
               ref={provided.innerRef} {...provided.droppableProps}>
              {this.state.files.map((file, index) => (
               <TaskTest key={file.link} file={file} index={index} />
              ))}
              {provided.placeholder}

             </TaskList>

             )}
            </Droppable>
        </Container>

        </div>
        );
  }
}

(This is where I add my input and fileReader to add files to my files array and iterate through those files using the .map() function in return() in render{})

task-test.jsx

export default class TaskTest extends React.Component {
    render() {
        return (
          <Draggable draggableId={this.props.file.link} index={this.props.index}>
           {(provided, snapshot) => (
            <Container
              {...provided.draggableProps}
              {...provided.dragHandleProps}
              ref={provided.innerRef}
              isDragging={snapshot.isDragging}
            >
            {this.props.file.name}
            </Container>
           )}
          </Draggable>
          );
     }

}

Upvotes: 1

Views: 6274

Answers (1)

Ed Lucas
Ed Lucas

Reputation: 7335

react-beautiful-dnd requires you to manage your own list, which means reordering the array after an item has been "dropped". Do accomplish this, there are a few things you need to add:

A function to handle the "drop"

  onDragEnd(result) {
    // dropped outside the list
    if (!result.destination) {
      return;
    }

    const files = reorder(
      this.state.files,
      result.source.index,
      result.destination.index
    );

    this.setState({
      files
    });
  }

Bind onDragEnd in your constructor

this.onDragEnd = this.onDragEnd.bind(this);

A function to reorder the array

const reorder = (list, startIndex, endIndex) => {
  const result = Array.from(list);
  const [removed] = result.splice(startIndex, 1);
  result.splice(endIndex, 0, removed);

  return result;
};

A DragDropContext around your droppable

<DragDropContext onDragEnd={this.onDragEnd}> 
    <Droppable droppableId={this.props.column.id}>
    ...

You can view an example here: https://codesandbox.io/s/k260nyxq9v

Upvotes: 2

Related Questions