準備
HOC なDragDropContext
で親コンポーネントをラップするか、DragDropContextProvider
を親コンポーネントマークアップに含める必要があります。ただし、DragDropContextProvider
は、react >= 16.0.0
かつreact-dnd >= 4.0.0
なバージョンである必要があります。
またブラウザ上で動作させる場合react-dnd-html5-backend
というパッケージも必要です。イベントハンドラーのようなものがまとまったもので、これを使って色々解決する感じのようです。react-dnd
とreact-dnd-html5-backend
は基本同じバージョンを使うようにしましょう。
ルートとしては以下のようになります。
DragDropContextProvider
import React from 'react';
import {DragDropContextProvider} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
class App extends React.Component {
render() {
return (
なんでもいい
);
}
}
export default App;
DragDropContext
import React from 'react';
import {DragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
class App extends React.Component {
render() {
return なんでもいい;
}
}
export default DragDropContext(HTML5Backend)(App);
少し分かりづらいですが、this.props
の値などは増えたりしないので注意です。
Drag and Drop (dnd)
Drag イベントを設定したいならDragSource
、 Drop イベントを設定したいならDropTarget
HOCを使います。どちらもreact-dnd
から提供されています。
共通項目
どちらとも第1引数にはtype
を指定します。これは処理をつなげる為に使われます。Foo
というタイプの Draggable 要素をFoo
というタイプの Droppable 要素へドロップした時に初めてドラッグからドロップという一連の処理が実行されます。
第3引数のconnect
はreact-redux
のconnect
と同じような動きです。react-dnd
で管理している状態(state
)をコンポーネントのprops
へ渡す為に使います。
第2引数のspec
は関数をまとめたオブジェクトを渡します。これらのキー名はreact-dnd
が指定している名前にする必要があり、その一部は必須項目になっています。
react-dnd
の関数の引数にあるprops
は HOC の対象となるコンポーネントのprops
の値、monitors
は、react-dnd.github.io/r/d/a/drag-source-monitorにある内容がオブジェクトになった形のものが入っています。props
などは対象先ですが、monitors
には対象元が入っているような感じです。
DragSource
spec
には、beginDrag(props, monitor, component)
, endDrag(props, monitor, component)
, canDrag(props, monitor)
, isDragging(props, monitor)
が設定でき、beginDrag
だけは必須項目です。それぞれ、
beginDrag
はドラッグが始まったタイミングに発火し、endDrag
はドラッグが終わったタイミングに発火します。beginDrag
やendDrag
戻り値は、monitor.getItem()
で取り出せるようになります。
canDrag
はドラッグできるかの動的制御に使います。
HOC の対象となるコンポーネントでは最小限、connect
でconnect.dragSource()
を受け取り Drap 対象とするJSX.Element
をその関数でラップする必要があります。
import {DragSource} from 'react-dnd';
DragSource(
'BLOCK',
{
beginDrag(props) {
console.log('beginDrag');
return props;
}
},
connect => {
return {
connectDragSource: connect.dragSource()
};
}
)(
class extends React.Component {
render() {
return this.props.connectDargSource(
);
}
}
);
DropTarget
先程 Drop 側のtype
をBLOCK
で指定したのでコチラ側もBLOCK
を指定します。
こちらのspec
は、drop(props, monitor, component)
, hover(props, monitor, component)
, canDrop(props, monitor)
となっており、canDrop
は概ねcanDrag
のものと同じです。
こちらには必須となっている項目はありません。
drop
は Dragable 要素を Droppable 要素の上で話した時に実行され、hover
は重なっている間連続で実行されます。
またこちらでは最小限、connect
でconnect.dropTarget(),
を受け取り Drop 対象とするJSX.Element
をその関数でラップする必要があります。
import {DropTarget} from 'react-dnd';
DropTarget(
'BLOCK',
{
drop(props) {
console.log('drop');
// onDrop は ` {}} />`
// のように渡したもの
// props.onDrop();
}
},
connect => {
return {
connectDrogTarget: connect.dropTarget()
};
}
)(
class extends React.Component {
render() {
return this.props.connectDrogTarget(
);
}
}
);
Drag も Drop もできる要素
connect.dragSource()
とconnect.drogTarget()
2つでラップしてあげればいけます。
const Draggable = DragSource(/* ... */);
const Droppable = DropTarget(/* ... */);
const DNDCompoennt = Droppable(
Droppable(
class extends React.Component {
render() {
const {connectDrogTarget, connectDragSource} = this.props;
return connectDropTarget(
connectDragSource(
)
);
}
}
)
);
仕上げ
DragDropContextProvider
より深い部分かDragDropContext
を適用したコンポーネント以下の部分で使うだけです。
class App extends React.Component {
render() {
return (
{
console.log('drop');
}}
/>
);
}
}