React DnDを使ってみた
March 22, 2017
React でドラッグ&ドロップを簡単に実装できるReact DnDを使ってみました。
一応、成果物はこちら ↓
環境
- MacOS Sierra 10.12.3
- Node.js v6.10.0
- React 15.4.2
- React DnD 2.2.4
1. プロジェクト作成と React DnD インストール
create-react-app
を使って React のプロジェクトを作り、yarn
で React DnD を入れます。
$ create-react-app react-dnd-sample
$ cd react-dnd-sample
$ yarn add react-dnd react-dnd-html5-backend
$ yarn start
2. 実装
今回は次のコンポーネントを作ります。
Knight
: ナイトのコマSquare
: チェス盤のマスBoard
: チェス盤BoardSquare
: チェス盤と各マスのつなぎ。Square
は表示だけ担当
コンポーネント以外には以下を用意します。
Game
: ドラッグ&ドロップを監視してレンダリングの指示を出す ObserverConstants
: 定数
まあまあ長くなってしまったので、コードはGistを確認してみてください。
3. 所感
既存のコンポーネントに対し、
ドラッグ対象ならDragSource
、ドロップ対象ならDropTarget
でラップして、
後は少しメソッドを足してあげるだけで使えるので、けっこう使いやすいなと思いました。
例えばKnight
クラスはドラッグされる対象なので、DragSource
でラップしています。
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, { Component, PropTypes } from 'react'; | |
import { ItemTypes } from './Constants'; | |
import { DragSource } from 'react-dnd'; | |
const knightSource = { | |
beginDrag(props) { | |
return {}; | |
} | |
}; | |
function collect(connect, monitor) { | |
return { | |
connectDragSource: connect.dragSource(), | |
connectDragPreview: connect.dragPreview(), | |
isDragging: monitor.isDragging() | |
} | |
} | |
class Knight extends Component { | |
componentDidMount() { | |
const img = new Image(); | |
img.src = 'data:image/png;base64,iVBORw0KGgoAAAA...'; // svg全体はチュートリアルを確認してください | |
img.onload = () => this.props.connectDragPreview(img); | |
} | |
render() { | |
const { connectDragSource, isDragging } = this.props; | |
return connectDragSource( | |
<div style={% raw %}{{ | |
opacity: isDragging ? 0.5 : 1, | |
fontSize: 25, | |
fontWeight: 'bold', | |
cursor: 'move' | |
}}{% endraw %}> | |
♘ | |
</div> | |
) | |
} | |
} | |
Knight.propTypes = { | |
connectDragSource: PropTypes.func.isRequired, | |
connectDragPreview: PropTypes.func.isRequired, | |
isDragging: PropTypes.bool.isRequired | |
} | |
export default DragSource(ItemTypes.KNIGHT, knightSource, collect)(Knight); |
今回使っているreact-dnd-html5-backend
だとタッチデバイスのときに動作しないのですが、
react-dnd-touch-backendというのもあるみたいなので次使ってみたいです。