Reputation: 2625
I am starting to learn React Drag and Drop from http://react-dnd.github.io/react-dnd/docs-tutorial.html
But I am having problems understanding the tutorial. Next are all the files I created but at compilation I get:
dragDropBundle.js:830 Warning: Failed prop type: The prop
`connectDropTarget` is marked as required in `BoardSquare`, but its value is `undefined`.
in BoardSquare (created by Board)
in Board (created by DragDropContext(Board))
in DragDropContext(Board)
and
dragDropBundle.js:31408 Uncaught TypeError: connectDropTarget is not a function
at BoardSquare.render (dragDropBundle.js:31408)
at dragDropBundle.js:16370
Can someone explain me please what is wrong? I am reading this tutorial several times and hitting the wall with it.
Here it is the content of my file entry.js
from where my program starts:
import React from "react";
import ReactDOM from "react-dom";
import Square from "./Square.jsx";
import Board from "./Board.jsx";
import Knight from "./Knight.jsx";
import { observe } from "./Game.jsx";
import { canMoveKnight, moveKnight } from "./Game.jsx";
const rootEl = document.getElementById("root");
observe(knightPosition =>
ReactDOM.render(<Board knightPosition={knightPosition} />, rootEl)
);
Here it is the content of my file Board.jsx
:
import React, { Component } from "react";
import { DragDropContext } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
import PropTypes from "prop-types";
import Square from "./Square.jsx";
import Knight from "./Knight.jsx";
import { canMoveKnight, moveKnight } from "./Game.jsx";
import { BoardSquare } from "./BoardSquare.jsx";
export class Board extends Component {
renderPiece(x, y) {
const [knightX, knightY] = this.props.knightPosition;
if (x === knightX && y === knightY) {
return <Knight />;
}
}
renderSquare(i) {
const x = i % 8;
const y = Math.floor(i / 8);
return (
<div key={i} style={{ width: "12.5%", height: "12.5%" }}>
<BoardSquare x={x} y={y}>
{this.renderPiece(x, y)}
</BoardSquare>
</div>
);
}
handleSquareClick(toX, toY) {
if (canMoveKnight(toX, toY)) {
moveKnight(toX, toY);
}
}
render() {
console.log(this.props.knightPosition);
const squares = [];
for (let i = 0; i < 64; i++) {
squares.push(this.renderSquare(i));
}
return (
<div
style={{
width: "100%",
height: "100%",
display: "flex",
flexWrap: "wrap"
}}
>
{squares}
</div>
);
}
}
Board.propTypes = {
knightPosition: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired
};
export default DragDropContext(HTML5Backend)(Board);
Here it is the content of my file Knight.jsx
:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { ItemTypes } from "./Constants.jsx";
import { DragSource } from "react-dnd";
const knightSource = {
beginDrag(props) {
return {};
}
};
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
};
}
class Knight extends Component {
render() {
const { connectDragSource, isDragging } = this.props;
return connectDragSource(
<div
style={{
opacity: isDragging ? 0.5 : 1,
fontSize: 25,
fontWeight: "bold",
cursor: "move"
}}
>
♘
</div>
);
}
}
Knight.propTypes = {
connectDragSource: PropTypes.func.isRequired,
isDragging: PropTypes.bool.isRequired
};
export default DragSource(ItemTypes.KNIGHT, knightSource, collect)(Knight);
Here it is the content of my file Square.jsx
:
import React, { Component } from "react";
import PropTypes from "prop-types";
export default class Square extends Component {
render() {
const { black } = this.props;
const fill = black ? "black" : "white";
const stroke = black ? "white" : "black";
return (
<div
style={{
backgroundColor: fill,
color: stroke,
width: "100%",
height: "100%"
}}
>
{this.props.children}
</div>
);
}
}
Square.propTypes = {
black: PropTypes.bool
};
Here it is the content of my file: BoardSquare.jsx
import React, { Component } from "react";
import PropTypes from "prop-types";
import Square from "./Square.jsx";
import { canMoveKnight, moveKnight } from "./Game.jsx";
import { ItemTypes } from "./Constants.jsx";
import { DropTarget } from "react-dnd";
const squareTarget = {
drop(props) {
moveKnight(props.x, props.y);
}
};
function collect(connect, monitor) {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()
};
}
export class BoardSquare extends Component {
render() {
const { x, y, connectDropTarget, isOver } = this.props;
const black = (x + y) % 2 === 1;
return connectDropTarget(
<div
style={{
position: "relative",
width: "100%",
height: "100%"
}}
>
<Square black={black}>{this.props.children}</Square>
{isOver && (
<div
style={{
position: "absolute",
top: 0,
left: 0,
height: "100%",
width: "100%",
zIndex: 1,
opacity: 0.5,
backgroundColor: "yellow"
}}
/>
)}
</div>
);
}
}
BoardSquare.propTypes = {
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
connectDropTarget: PropTypes.func.isRequired,
isOver: PropTypes.bool.isRequired
};
export default DropTarget(ItemTypes.KNIGHT, squareTarget, collect)(BoardSquare);
Upvotes: 2
Views: 408
Reputation: 35491
Your error is caused by this props type setting:
BoardSquare.propTypes = {
// ...
connectDropTarget: PropTypes.func.isRequired,
// ^^^^^^^^^^^ property connectDropTarget is market as required
// ...
};
Which marks connectDropTarget
as a required prop in BoardSquare
.
What should happen is that, because you wrap BoardSquare
into a DropTarget
, the DropTarget
knows to set the value for connectDropTarget
in the props of BoardSquare
through the collect
function.
However, what you are doing is using the barebones BoardSquare
function, not the one wrapped in DropTarget
.
// Board.jsx
import {BoardSquare} from './BoardSquare.jsx';
// ^ ^ you are importing BoardSquare, not DropTarget(...)(BoardSquare)
This should be:
// Board.jsx
import BoardSquare from './BoardSquare.jsx';
So this means that, since you're not using the component wrapped in DropTarget
, nothing is calling the collect
function and thus nothing is setting the connectDropTarget
prop.
To clean things up, you can probably remove the export
of the barebones class from BoardSquare
and only export the class wrapped in DropTarget
:
// BoardSquare.jsx
export class BoardSquare extends Component {
// ^^^ remove this export statement
Upvotes: 2