2017-08-26 7 views
0

Je travaille sur une version simple de ReactDND avant d'implémenter ce code dans mon uploader d'image.Réagir DND - Impossible d'ajouter un nouvel élément à l'état après un événement de glisser-déposer

Chaque fois qu'une image est ajoutée, elle est ajoutée à l'état et transmise à ReactDND pour être déplacée et également droppable (afin que les utilisateurs puissent réorganiser leurs images).

Tout fonctionne très bien, sauf pour une chose. Le problème que j'ai est après avoir ajouté plusieurs images, c'est qu'une fois que je fais glisser et déposer et l'image (fonctionne), l'état ne met plus à jour pour ReactDND et je ne peux pas ajouter de nouvelles images.

Voici mon code ci-dessous (note que je suis juste en utilisant un bouton pour ajouter des éléments supplémentaires à l'état):

Composant principal:

import React from 'react'; 

// Drag and drop stuff 
import { DragDropContext } from 'react-dnd'; 
import HTML5Backend from 'react-dnd-html5-backend'; 
import Container from './Container'; 

class ImageUploader extends React.Component { 

    constructor(props) { 
     super(props); 

     this.state = { 
      list: [], 
      listCount: 1 
     }; 

     this.onAddItem = this.onAddItem.bind(this); 

    } 

    onAddItem(e) { 
     e.preventDefault(); 

     var listArray = this.state.list; 
     var buildObject = { 
      text: 'Jeremy' + this.state.listCount.toString(), 
      age: '25', 
      id: this.state.listCount 
     }; 
     listArray.push(buildObject); 

     let newListCount = this.state.listCount + 1; 

     this.setState({ 
      list: listArray, 
      listCount: newListCount 
     }); 

     console.log(this.state.list); 
    } 

    render() { 

     return (
      <div> 
       <h1>Add to List</h1> 
       <button onClick={this.onAddItem}>Add Item</button> 
       <h1>The List</h1> 
       <Container id={1} list={this.state.list} /> 
      </div> 
     ) 
    } 
} 
export default DragDropContext(HTML5Backend)(ImageUploader); 

Container:

import React, { Component } from 'react'; 
import update from 'react/lib/update'; 
import Card from './Card'; 
import { DropTarget } from 'react-dnd'; 

class Container extends Component { 

    constructor(props) { 
     super(props); 
     this.state = { cards: props.list }; 
    } 

    pushCard(card) { 
     this.setState(update(this.state, { 
      cards: { 
       $push: [ card ] 
      } 
     })); 
    } 

    removeCard(index) { 
     this.setState(update(this.state, { 
      cards: { 
       $splice: [ 
        [index, 1] 
       ] 
      } 
     })); 
    } 

    moveCard(dragIndex, hoverIndex) { 
     const { cards } = this.state; 
     const dragCard = cards[dragIndex]; 

     this.setState(update(this.state, { 
      cards: { 
       $splice: [ 
        [dragIndex, 1], 
        [hoverIndex, 0, dragCard] 
       ] 
      } 
     })); 
    } 


    render() { 
     const { cards } = this.state; 
     const { canDrop, isOver, connectDropTarget } = this.props; 
     const isActive = canDrop && isOver; 
     const style = { 
      width: "200px", 
      height: "404px", 
      border: '1px dashed gray' 
     }; 

     const backgroundColor = isActive ? 'lightgreen' : '#FFF'; 

     return connectDropTarget(
      <div className="houzes-dropbox"> 
       {cards.map((card, i) => { 
        return (
         <Card 
          key={card.id} 
          index={i} 
          listId={this.props.id} 
          card={card} 
          removeCard={this.removeCard.bind(this)} 
          moveCard={this.moveCard.bind(this)} /> 
        ); 
       })} 
      </div> 
     ); 
    } 
} 

const cardTarget = { 
    drop(props, monitor, component) { 
     const { id } = props; 
     const sourceObj = monitor.getItem(); 
     if (id !== sourceObj.listId) component.pushCard(sourceObj.card); 
     return { 
      listId: id 
     }; 
    } 
} 

export default DropTarget("CARD", cardTarget, (connect, monitor) => ({ 
    connectDropTarget: connect.dropTarget(), 
    isOver: monitor.isOver(), 
    canDrop: monitor.canDrop() 
}))(Container); 

Carte:

import React, { Component } from 'react'; 
import { findDOMNode } from 'react-dom'; 
import { DragSource, DropTarget } from 'react-dnd'; 
import flow from 'lodash/flow'; 

const style = { 
    border: '1px dashed grey', 
    padding: '0.5rem 1rem', 
    margin: '.5rem', 
    backgroundColor: 'white', 
    cursor: 'move' 
}; 

class Card extends Component { 

    render() { 
     const { card, isDragging, connectDragSource, connectDropTarget } = this.props; 
     const opacity = isDragging ? 0 : 1; 

     // Background URL 
     let backgroundUrl = { 
      backgroundImage: "url(" + "http://localhost:4000/uploads/2017/8/a3ff91dc-2f80-42f7-951a-e9a74bf954d7-1200x800.jpeg" + ")" 
     }; 

     console.log(card); 

     return connectDragSource(connectDropTarget(


      <div className={`uploadedImageWrapper col-md-6 col-sm-12`}> 
       <div className="uploadedImage"> 
        <span style={backgroundUrl} /> 
        {card.text} 
        {card.age} 
       </div> 
      </div> 


     )); 
    } 
} 

const cardSource = { 

    beginDrag(props) { 
     return { 
      index: props.index, 
      listId: props.listId, 
      card: props.card 
     }; 
    }, 

    endDrag(props, monitor) { 
     const item = monitor.getItem(); 
     const dropResult = monitor.getDropResult(); 

     if (dropResult && dropResult.listId !== item.listId) { 
      props.removeCard(item.index); 
     } 
    } 
}; 

const cardTarget = { 

    hover(props, monitor, component) { 
     const dragIndex = monitor.getItem().index; 
     const hoverIndex = props.index; 
     const sourceListId = monitor.getItem().listId; 

     // Don't replace items with themselves 
     if (dragIndex === hoverIndex) { 
      return; 
     } 

     // Determine rectangle on screen 
     const hoverBoundingRect = findDOMNode(component).getBoundingClientRect(); 

     // Get vertical middle 
     const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top)/2; 

     // Determine mouse position 
     const clientOffset = monitor.getClientOffset(); 

     // Get pixels to the top 
     const hoverClientY = clientOffset.y - hoverBoundingRect.top; 

     // Only perform the move when the mouse has crossed half of the items height 
     // When dragging downwards, only move when the cursor is below 50% 
     // When dragging upwards, only move when the cursor is above 50% 

     // Dragging downwards 
     if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { 
      return; 
     } 

     // Dragging upwards 
     if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { 
      return; 
     } 

     // Time to actually perform the action 
     if (props.listId === sourceListId) { 
      props.moveCard(dragIndex, hoverIndex); 

      // Note: we're mutating the monitor item here! 
      // Generally it's better to avoid mutations, 
      // but it's good here for the sake of performance 
      // to avoid expensive index searches. 
      monitor.getItem().index = hoverIndex; 
     } 
    } 
}; 

export default flow(
    DropTarget("CARD", cardTarget, connect => ({ 
     connectDropTarget: connect.dropTarget() 
    })), 
    DragSource("CARD", cardSource, (connect, monitor) => ({ 
     connectDragSource: connect.dragSource(), 
     isDragging: monitor.isDragging() 
    })) 
)(Card); 

Donc, juste pour récapituler, je peux ajouter des éléments à énoncer, et ils deviennent draggable et droppable. Mais après avoir traîné et déposé un élément, je ne peux plus ajouter d'éléments à énoncer.

Des idées sur ce que serait la solution? Qu'est-ce que je fais mal?

Merci d'avoir parcouru ceci, et toutes les réponses. À votre santé.

Répondre

6

@Notorious. J'ai vérifié votre code dans mon côté et résolu le problème. Lorsque vous faites glisser un élément qui modifie l'état du conteneur mais pas l'état de ImageUploader.

J'ai donc fait une fonction pour informer l'état du conteneur a changé. J'ai également inséré la fonction componentWillReceiveProps() dans Container et mis à jour l'état de Container dans cette fonction.

Enfin le problème résolu.

Voici le code modifié.

Composant principal:

import React from 'react'; 

// Drag and drop stuff 
import {DragDropContext} from 'react-dnd'; 
import HTML5Backend from 'react-dnd-html5-backend'; 
import Container from './Container'; 

class ImageUploader extends React.Component { 

    constructor(props) { 
    super(props); 

    this.state = { 
     list: [], 
     listCount: 1 
    }; 

    this.onAddItem = this 
     .onAddItem 
     .bind(this); 

    this.listChanged = this.listChanged.bind(this); 

    } 

    onAddItem(e) { 
    e.preventDefault(); 

    var listArray = this.state.list; 
    var buildObject = { 
     text: 'Jeremy' + this 
     .state 
     .listCount 
     .toString(), 
     age: '25', 
     id: this.state.listCount 
    }; 
    listArray.push(buildObject); 

    let newListCount = this.state.listCount + 1; 

    this.setState({list: listArray, listCount: newListCount}); 
    } 

    listChanged(newList) { 
    this.setState({ 
     list: newList 
    }) 
    } 

    render() { 

    return (
     <div> 
     <h1>Add to List</h1> 
     <button onClick={this.onAddItem}>Add Item</button> 
     <h1>The List</h1> 
     <Container id={1} list={this.state.list} listChanged={this.listChanged}/> 
     </div> 
    ) 
    } 
} 
export default DragDropContext(HTML5Backend)(ImageUploader); 

Container:

import React, { Component } from 'react'; 
import update from 'react/lib/update'; 
import Card from './Card'; 
import { DropTarget } from 'react-dnd'; 

class Container extends Component { 

    constructor(props) { 
     super(props); 
      this.state = { cards: this.props.list }; 
    } 

    pushCard(card) { 
     this.setState(update(this.state, { 
      cards: { 
       $push: [ card ] 
      } 
     })); 
    } 

    removeCard(index) { 
     this.setState(update(this.state, { 
      cards: { 
       $splice: [ 
        [index, 1] 
       ] 
      } 
     })); 
    } 

    moveCard(dragIndex, hoverIndex) { 
     const { cards } = this.state; 
     const dragCard = cards[dragIndex]; 

     this.setState(update(this.state, { 
      cards: { 
       $splice: [ 
        [dragIndex, 1], 
        [hoverIndex, 0, dragCard] 
       ] 
      } 
     })); 
    } 

    componentWillReceiveProps(nextProps) { 
     // You don't have to do this check first, but it can help prevent an unneeded render 
     if (nextProps.list !== this.state.cards) { 
      this.props.listChanged(this.state.cards); 
     } 
    } 


    render() { 
     const { cards } = this.state; 
     const { canDrop, isOver, connectDropTarget } = this.props; 
     const isActive = canDrop && isOver; 
     const style = { 
      width: "200px", 
      height: "404px", 
      border: '1px dashed gray' 
     }; 

     const backgroundColor = isActive ? 'lightgreen' : '#FFF'; 

     return connectDropTarget(
      <div className="houzes-dropbox"> 
       {cards.map((card, i) => { 
        return (
         <Card 
          key={card.id} 
          index={i} 
          listId={this.props.id} 
          card={card} 
          removeCard={this.removeCard.bind(this)} 
          moveCard={this.moveCard.bind(this)} /> 
        ); 
       })} 
      </div> 
     ); 
    } 
} 

const cardTarget = { 
    drop(props, monitor, component) { 
     const { id } = props; 
     const sourceObj = monitor.getItem(); 
     if (id !== sourceObj.listId) component.pushCard(sourceObj.card); 
     return { 
      listId: id 
     }; 
    } 
} 

export default DropTarget("CARD", cardTarget, (connect, monitor) => ({ 
    connectDropTarget: connect.dropTarget(), 
    isOver: monitor.isOver(), 
    canDrop: monitor.canDrop() 
}))(Container); 

Je suis vraiment heureux si cela vous a aidé.

Merci d'avoir lu mon message.

Vladimir

+0

S'il vous plaît, essayez d'ajouter le code corrigé pour améliorer la réponse! –

+0

J'ai mis à jour ma réponse – superdev

+0

agréable, upvoting !! ;) –