git clone https://gist.github.com/ed6714519284d36792ba.git try-dnd
cd try-dnd
npm install
npm start
# http://0.0.0.0:59798/webpack-dev-server/
# webpack result is served from /
# content is served from /Users/59naga/Downloads/try-dnd
Last active
October 6, 2016 12:48
-
-
Save 59naga/ed6714519284d36792ba to your computer and use it in GitHub Desktop.
react-dnd minimal example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Document</title> | |
</head> | |
<body> | |
<script src="bundle.js"></script> | |
<main></main> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import ReactDOM from 'react-dom' | |
import {DragDropContext,DropTarget,DragSource} from 'react-dnd' | |
import ReactDnDHTML5Backend from 'react-dnd-html5-backend' | |
import ReactDnDTouchBackend from 'react-dnd-touch-backend' | |
import EventEmitter from 'events' | |
import update from 'react-addons-update' | |
const isMobile= navigator.userAgent.match(/(Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone)/i) !== null | |
class Action extends EventEmitter{ | |
exchange(aId,bId){ | |
this.emit('exchange',aId,bId) | |
} | |
} | |
class Store extends EventEmitter{ | |
constructor(action){ | |
super() | |
this.data= { | |
items: [ | |
{id:0,text:'Lorem ipsum dolor sit amet'}, | |
{id:1,text:'consectetur adipisicing elit'}, | |
{id:2,text:'Voluptatibus repellendus vitae officia'}, | |
{id:3,text:'earum ea eligendi voluptates quidem harum'}, | |
{id:4,text:'voluptas numquam aliquam cum eaque?'}, | |
], | |
} | |
action.on('exchange',::this.onExchange) | |
} | |
onExchange(aId,bId){ | |
let aItem= this.data.items.filter(item => item.id === aId)[0] | |
let aIndex= this.data.items.indexOf(aItem) | |
let bItem= this.data.items.filter(item => item.id === bId)[0] | |
let bIndex= this.data.items.indexOf(bItem) | |
this.data= update(this.data,{items:{ | |
$splice: [[aIndex,1,bItem]], | |
}}) | |
this.data= update(this.data,{items:{ | |
$splice: [[bIndex,1,aItem]], | |
}}) | |
this.emit('change') | |
} | |
get(){ | |
return this.data | |
} | |
} | |
@DragDropContext(isMobile? ReactDnDTouchBackend: ReactDnDHTML5Backend) | |
class Sortable extends React.Component{ | |
constructor(props){ | |
super(props) | |
this.state= this.props.store.get() | |
this._onChange= ::this.onChange | |
} | |
onChange(){ | |
this.setState(this.props.store.get()) | |
} | |
componentDidMount(){ | |
this.props.store.on('change',this._onChange) | |
} | |
componentWillUnmount(){ | |
this.props.store.removeListener('change',this._onChange) | |
} | |
render(){ | |
return( | |
<ul> | |
{ | |
this.state.items.map((item,i) => | |
<Item action={this.props.action} id={item.id} key={i}>{item.text}</Item> | |
) | |
} | |
</ul> | |
) | |
} | |
} | |
@DropTarget('item',{ | |
hover(hoverProps,monitor,hoverComponent){ | |
let dragProps= monitor.getItem() | |
if(hoverProps.id === dragProps.id){ | |
return | |
} | |
hoverProps.action.emit('exchange',dragProps.id,hoverProps.id) | |
}, | |
},(connect)=>{ | |
return { | |
connectDropTarget: connect.dropTarget(), | |
} | |
}) | |
@DragSource('item',{ | |
beginDrag(props){ | |
return props | |
} | |
},(connect,monitor)=>{ | |
return { | |
connectDragSource: connect.dragSource(), | |
isDragging: monitor.isDragging(), | |
} | |
}) | |
class Item extends React.Component{ | |
render(){ | |
return this.props.connectDragSource(this.props.connectDropTarget( | |
<li> | |
{this.props.children} | |
</li> | |
)) | |
} | |
} | |
addEventListener('load',()=>{ | |
const action= new Action | |
const store= new Store(action) | |
ReactDOM.render(<Sortable action={action} store={store} />,document.querySelector('main')) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "try-dnd", | |
"scripts": { | |
"start": "webpack-dev-server --port 59798 --host 0.0.0.0", | |
"build": "webpack" | |
}, | |
"dependencies": { | |
"react": "^0.14.2", | |
"react-addons-update": "^0.14.2", | |
"react-dnd": "^2.0.2", | |
"react-dnd-html5-backend": "^2.0.0", | |
"react-dnd-touch-backend": "^0.2.0", | |
"react-dom": "^0.14.2" | |
}, | |
"devDependencies": { | |
"babel-core": "^5.8.33", | |
"babel-loader": "^5.3.3", | |
"webpack": "^1.12.4", | |
"webpack-dev-server": "^1.12.1" | |
}, | |
"babel": { | |
"stage": 0 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import webpack from 'webpack' | |
export default { | |
entry: './index.js', | |
output: './bundle.js', | |
module: { | |
loaders: [ | |
{ | |
test: /\.js$/, | |
exclude: /node_modules/, | |
loaders: ['babel-loader'], | |
}, | |
], | |
}, | |
devtool: '#source-map', | |
plugins: [ | |
// new webpack.optimize.UglifyJsPlugin({compress:{warnings:false}}), | |
new webpack.optimize.OccurenceOrderPlugin(), | |
new webpack.HotModuleReplacementPlugin(), | |
new webpack.NoErrorsPlugin() | |
], | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment