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 (); }}export default DragDropContext(HTML5Backend)(App);{ /* */} Welcome to React
{ /* {this.state.items.map((item, index) => ({ /*- this.deleteItem(id)} /> ))} */}
*/} { this.state.cards.map((card, i) => ())}
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({text}), ) ); }}export default flow( DragSource( 'card', cardSource, (connect, monitor) => ({ connectDragSource: connect.dragSource(), isDragging: monitor.isDragging(), }), ), DropTarget('card', cardTarget, (connect) => ({ connectDropTarget: connect.dropTarget(), })))(Card);