2017-08-26 132 views
0

我正在使用ReactDND的简单版本,然后将此代码实施到我的图像上传程序中。React DND - 在拖放事件后无法添加新项目到状态

每次添加图像时,它都会添加到状态并传递给ReactDND,以便它可拖动并可放下(以便用户可以重新排列图像)。

一切都很好,除了一件事。我遇到的问题是在添加多个图像后,一旦我拖放和图像(工作),状态不再更新ReactDND,我不能添加新图像。

这里是下方(注意:我只是用一个按钮来添加额外的项目状态)我的代码:

主要成分:

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); 

集装箱:

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); 

卡:

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); 

所以我们只需要回顾一下,我可以添加项目到状态,并且它们可以拖动和拖放。但是在拖拽一个元素之后,我再也不能再添加项目来陈述了。

任何有关解决方案的想法?我究竟做错了什么?

感谢您通过此查看和任何答案。干杯。

回答

6

@Notorious。

我检查了你的代码,并解决了问题。 当您拖放更改Container状态但不是ImageUploader状态的元素时。

所以我做了一个函数来告知Container的状态已经改变了。 此外,我将ComponentWillReceiveProps()函数插入Container,并更新了该函数中Container的状态。

最后问题解决了。

以下是更改后的代码。

主要成分:

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); 

集装箱:

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); 

我真的很高兴,如果这有助于你。

感谢您阅读我的文章。

Vladimir

+0

请尝试添加更正的代码来改善答案! –

+0

我已经更新了我的回答 – superdev

+0

不错,upvoting! ;) –