How to implement drag and drop behaviour in React

感情迁移 提交于 2020-01-04 04:10:10

问题


I'm trying to implement drag and drop behaviour using React and react-beautiful-dnd library.

I want to chose some images using react-dropzone library and after choosing images I show thumbnails on the right side of the screen and after that I want to be able to drag one of those thumbnails to the left side and drop it to one of those containers.

My code is as follows:

import React, { Component } from "react";
import ReactDOM from "react-dom";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import Dropzone from "react-dropzone";
import { Animated } from "react-animated-css";
import { orderBy } from "lodash";
import UUID from "uuid";
import "./styles.css";

const animationIn = "fadeInDown";
const animationOut = "fadeOutUp";
const animationDuration = 400; // in ms

const pictureTypes = [
  {
    title: "3/4 front left",
    imageOverlay: "https://via.placeholder.com/100",
    item: "front-left",
    mandatory: true,
    image: null,
    priority: 1
  },
  {
    title: "3/4 rear right",
    imageOverlay: "https://via.placeholder.com/100",
    item: "rear-right",
    mandatory: true,
    image: null,
    priority: 2
  },
  {
    title: "Inside door right",
    imageOverlay: "https://via.placeholder.com/100",
    item: "front-door-right-i",
    mandatory: true,
    image: null,
    priority: 3
  }
];

class App extends Component {
  constructor(props) {
    super(props);

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

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

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

  addFilesToState(files) {
    let files_with_preview = [];
    files.map(file => {
      file["preview"] = URL.createObjectURL(file);
      files_with_preview.push(file);
      this.setState({ [`visibleAnimate${file.path}`]: true });
    });

    const new_files = [...this.state.files, ...files_with_preview];
    this.setState({ files: new_files });
  }

  renderPreviews(files) {
    if (files.length < 1)
      return <div>Drag and drop some files to see them here.</div>;

    return (
      <div style={{ display: "flex", flexDirection: "column" }}>
        <div>Chosen pictures</div>
        <div style={{ display: "flex", flexDirection: "row" }}>
          {files.map((file, index) => {
            return (
              <Draggable key={UUID.v4()} draggableId={UUID.v4()} index={index}>
                {provided => (
                  <div
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    <img
                      src={file.preview}
                      alt={file.path}
                      style={{ width: 80 }}
                    />
                  </div>
                )}
              </Draggable>
            );
          })}
        </div>
      </div>
    );
  }

  handlePictureTypesDrop(file, pictureType) {
    const file_blob = URL.createObjectURL(file);
    const updated_picture_type = {
      ...this.state.pictureTypes.find(pt => pt.item === pictureType.item),
      image: file_blob
    };
    const updated_picture_types = [
      ...this.state.pictureTypes.filter(pt => pt.item !== pictureType.item),
      updated_picture_type
    ];
    let new_picture_types = [...updated_picture_types];

    this.setState({ pictureTypes: new_picture_types });
  }

  renderPictureTypes() {
    const { allowed_types } = this.props;
    const { pictureTypes } = this.state;
    const self = this;

    return orderBy(pictureTypes, "priority").map(pt => {
      return (
        <div style={{ width: "25%", marginRight: 5 }}>
          <Dropzone
            onDrop={files => self.handlePictureTypesDrop(files[0], pt)}
            accept={allowed_types}
            multiple={false}
          >
            {({ getRootProps, getInputProps }) => (
              <div {...getRootProps()}>
                <input {...getInputProps()} />
                <div className="picture-types-wrapper">
                  <div>
                    <img
                      src={pt.image !== null ? pt.image : pt.imageOverlay}
                      alt={pt.title}
                    />
                  </div>
                  <div style={{ fontSize: "0.65rem" }}>{pt.title}</div>
                </div>
              </div>
            )}
          </Dropzone>
        </div>
      );
    });
  }

  // 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 { files } = this.state;
    const self = this;
    return (
      <DragDropContext onDragEnd={this.onDragEnd}>
        <Droppable droppableId="droppable">
          {provided => (
            <div
              key="droppable"
              {...provided.droppableProps}
              ref={provided.innerRef}
            >
              <Dropzone
                onDrop={files => self.addFilesToState(files)}
                accept="image/jpeg, image/png"
              >
                {({ getRootProps, getInputProps }) => (
                  <section className="drag-drop-section">
                    <div {...getRootProps()}>
                      <input {...getInputProps()} />
                      <p className="drag-drop-text">
                        Drag 'n' drop some files here, or click to select files
                      </p>
                    </div>
                  </section>
                )}
              </Dropzone>

              <div
                style={{ display: "flex", flexDirection: "row", marginTop: 10 }}
              >
                <div style={{ display: "flex", flexDirection: "row" }}>
                  {self.renderPictureTypes()}
                </div>
                <div className="flex w-1/2 pl-2">
                  {self.renderPreviews(files)}
                </div>
              </div>
              {provided.placeholder}
            </div>
          )}
        </Droppable>
      </DragDropContext>
    );
  }
}

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

Here is the example code on codesandbox.

The photo's are successfully added to the right side where I render the thumbnails but I cant drag one of them then to the left side.

Any idea how to solve it?

来源:https://stackoverflow.com/questions/56643338/how-to-implement-drag-and-drop-behaviour-in-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!