react dnd demo2
import React, { Component } from 'react'; import './App.css'; import Card from './Card'; import HTML5Backend from 'react-dnd-html5-backend' import { DragDropContext } from 'react-dnd' // const update = require('immutability-helper'); import update from 'react-addons-update'; class App extends Component { state = { cards: [ { id: 1, text: 'Write a cool JS library', }, { id: 2, text: 'Make it generic enough', }, { id: 3, text: 'Write README', }, { id: 4, text: 'Create some examples', }, { id: 5, text: 'Spam in Twitter and IRC to promote it (note that this element is taller than the others)', }, { id: 6, text: '???', }, { id: 7, text: 'PROFIT', }, ], } deleteItem = id => { this.setState(prevState => { return { items: prevState.items.filter(item => item.id !== id) } }) } moveCard = (dragIndex, hoverIndex) => { const { cards } = this.state const dragCard = cards[dragIndex] this.setState( update(this.state, { cards: { $splice: [[dragIndex, 1], [hoverIndex, 0, dragCard]], }, }), () => { console.log(this.state.cards); }) } render() { return ( <div className="App"> <header className="App-header"> {/* <img src={logo} className="App-logo" alt="logo" /> */} <h1 className="App-title">Welcome to React</h1> </header> <div className="App-intro"> <div className="app-container"> <div className="item-container"> {/* {this.state.items.map((item, index) => ( <Item key={item.id} item={item} handleDrop={(id) => this.deleteItem(id)} /> ))} */} </div> {/* <Target /> */} </div> <div className="card-container"> {this.state.cards.map((card, i) => ( <Card key={card.id} index={i} id={card.id} text={card.text} moveCard={this.moveCard} /> ))} </div> </div> </div> ); } } export default DragDropContext(HTML5Backend)(App);
card
import React from 'react'; import PropTypes from 'prop-types'; import { findDOMNode } from 'react-dom'; import { DragSource, DropTarget, ConnectDropTarget, ConnectDragSource, DropTargetMonitor, DropTargetConnector, DragSourceConnector, DragSourceMonitor, } from 'react-dnd'; import { XYCoord } from 'dnd-core'; import flow from 'lodash/flow'; const style = { border: '1px dashed gray', padding: '0.5rem 1rem', marginBottom: '.5rem', backgroundColor: 'white', cursor: 'move', }; const cardSource = { beginDrag(props) { return { id: props.id, index: props.index, } }, }; const cardTarget = { hover(props, monitor, component) { const dragIndex = monitor.getItem().index const hoverIndex = props.index // 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 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; }, } class Card extends React.Component { static propTypes = { connectDragSource: PropTypes.func.isRequired, connectDropTarget: PropTypes.func.isRequired, index: PropTypes.number.isRequired, isDragging: PropTypes.bool.isRequired, id: PropTypes.any.isRequired, text: PropTypes.string.isRequired, moveCard: PropTypes.func.isRequired, } render() { const { text, isDragging, connectDragSource, connectDropTarget, } = this.props; const opacity = isDragging ? 0 : 1; return ( connectDragSource && connectDropTarget && connectDragSource( connectDropTarget(<div style={{ ...style, opacity }}>{text}</div>), ) ); } } export default flow( DragSource( 'card', cardSource, (connect, monitor) => ({ connectDragSource: connect.dragSource(), isDragging: monitor.isDragging(), }), ), DropTarget('card', cardTarget, (connect) => ({ connectDropTarget: connect.dropTarget(), })) )(Card);