Open6
react-dndについて
react-dndについて知って,モノにする
公式ドキュメント
公式のチュートリアル
DndProvider
最初にセットアップする必要があるのが,DndProvider.
これはアプリのトップ付近でマウントされている必要がある.
import React from 'react'
import { DndProvider } from 'react-dnd'
import { HTML5Backend } from 'react-dnd-html5-backend'
function Board() {
/* ... */
return <DndProvider backend={HTML5Backend}>...</DndProvider>
}
useDrag
ドラッグ可能にする(Draggable)
変数を宣言する
- propsObject -> isDragging
- ref関数 DOM要素を react-dnd にアタッチするために使われる.-> drag
useDragの引数(item, collect)
- item.typeproperty(必須) ドラッグされるアイテムの種類を指定する
- collect関数 ドラッグ&ドロップシステムの状態をコンポーネントで使用可能にする
const [{isDragging}, drag] = useDrag({
item: { type: 'knight' },
collect: monitor => ({
isDragging: !!monitor.isDragging(),
}),
})
全体
import React from 'react'
import { useDrag } from 'react-dnd'
function Knight() {
const [{isDragging}, drag] = useDrag({
item: { type: 'knight' },
collect: monitor => ({
isDragging: !!monitor.isDragging(),
}),
})
return (
<div
ref={drag}
style={{
opacity: isDragging ? 0.5 : 1,
fontSize: 25,
fontWeight: 'bold',
cursor: 'move',
}}
>
♘
</div>,
)
}
export default Knight
useDrop
ドロップターゲットを設定(Droppable)
同様にuseDropを使って変数を定義
const [{ isOver }, drop] = useDrop({
accept: 'knight',
drop: () => moveKnight(x, y),
collect: (monitor) => ({
isOver: !!monitor.isOver()
})
})
全体
import React from 'react'
import Square from './Square'
import { moveKnight } from './Game'
import { useDrop } from 'react-dnd'
function BoardSquare({ x, y, children }) {
const black = (x + y) % 2 === 1
const [{ isOver }, drop] = useDrop({
accept: 'knight',
drop: () => moveKnight(x, y),
collect: monitor => ({
isOver: !!monitor.isOver(),
}),
})
return (
<div
ref={drop}
style={{
position: 'relative',
width: '100%',
height: '100%',
}}
>
<Square black={black}>{children}</Square>
{isOver && (
<div
style={{
position: 'absolute',
top: 0,
left: 0,
height: '100%',
width: '100%',
zIndex: 1,
opacity: 0.5,
backgroundColor: 'yellow',
}}
/>
)}
</div>,
)
}
export default BoardSquare
簡単に自分でやってみた
React.FC + TS
親コンポーネント:Board
子(ドラッグ): DragSource
子(ドロップ):DropTarget
(react, typescript未熟なので,良くない記述をしているかも)
Board.tsx
import React, { useState } from "react";
import DragSource from "./DragSource";
import DropTarget from "./DropTarget";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
const Board: React.FC = () => {
const [inObject, SetinObject] = useState(false);
const handleDrop = () => {
SetinObject(true);
};
return (
<DndProvider backend={HTML5Backend}>
{inObject ? null : <DragSource />}
↓ここにドロップできます
<DropTarget onDrop={handleDrop}>
{inObject ? <DragSource /> : null}
</DropTarget>
</DndProvider>
);
};
export default Board;
DragSource.tsx
import React from "react";
import { useDrag } from "react-dnd";
const DragSource: React.FC = () => {
const [{ isDragging }, drag] = useDrag({
item: { type: "dragobject" },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
});
return (
<div
style={{
backgroundColor: "black",
color: "white",
width: "100px",
height: "100px",
margin: "1em",
opacity: isDragging ? 0.5 : 1,
cursor: "move",
}}
ref={drag}
>
ドラッグできます
</div>
);
};
export default DragSource;
DropTarget.tsx
import React from "react";
import { useDrop } from "react-dnd";
interface Props {
onDrop: any;
}
const DropTarget: React.FC<Props> = ({ onDrop, children }) => {
const [isOver, drop] = useDrop({
accept: "dragobject",
drop: () => onDrop(),
collect: (monitor) => ({
isOver: !!monitor.isOver(),
}),
});
return (
<div
ref={drop}
style={{
width: "150px",
height: "150px",
border: "4px solid",
margin: "1em",
}}
>
{children}
</div>
);
};
export default DropTarget;