Skip to content

Instantly share code, notes, and snippets.

@59naga
Last active October 6, 2016 12:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 59naga/ed6714519284d36792ba to your computer and use it in GitHub Desktop.
Save 59naga/ed6714519284d36792ba to your computer and use it in GitHub Desktop.
react-dnd minimal example
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="bundle.js"></script>
<main></main>
</body>
</html>
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'))
})
{
"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
}
}
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