saitoxu.io

AboutTwitterGitHub

React DnDを使ってみた

March 22, 2017

React でドラッグ&ドロップを簡単に実装できるReact DnDを使ってみました。

前回同様、公式のチュートリアルに従ってます。

一応、成果物はこちら ↓

react-dnd-sample

環境

  • 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 : ドラッグ&ドロップを監視してレンダリングの指示を出す Observer
  • Constants : 定数

まあまあ長くなってしまったので、コードはGistを確認してみてください。

3. 所感

既存のコンポーネントに対し、 ドラッグ対象ならDragSource、ドロップ対象ならDropTargetでラップして、 後は少しメソッドを足してあげるだけで使えるので、けっこう使いやすいなと思いました。

例えばKnightクラスはドラッグされる対象なので、DragSourceでラップしています。

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);
view raw Knight.js hosted with ❤ by GitHub

今回使っているreact-dnd-html5-backendだとタッチデバイスのときに動作しないのですが、 react-dnd-touch-backendというのもあるみたいなので次使ってみたいです。


© 2021, Yosuke Saito