我开始从http://react-dnd.github.io/react-dnd/docs-tutorial.html学习React拖放
但是我在理解本教程时遇到了问题。接下来是我创建的所有文件,但在编译时会得到:
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)
和
dragDropBundle.js:31408 Uncaught TypeError: connectDropTarget is not a function
at BoardSquare.render (dragDropBundle.js:31408)
at dragDropBundle.js:16370
有人可以解释一下我怎么了吗?我正在阅读本教程几次,并且碰壁了。
这是程序开始时文件
entry.js
的内容: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)
);
这是我的文件
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);
这是我的文件
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);
这是我的文件
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
};
这是我文件的内容:
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);
最佳答案
您的错误是由以下道具类型设置引起的:
BoardSquare.propTypes = {
// ...
connectDropTarget: PropTypes.func.isRequired,
// ^^^^^^^^^^^ property connectDropTarget is market as required
// ...
};
在
connectDropTarget
中将BoardSquare
标记为必需的道具。应该发生的是,因为将
BoardSquare
包装到DropTarget
中,所以DropTarget
知道通过connectDropTarget
函数在BoardSquare
的属性中设置collect
的值。但是,您正在使用的是准系统
BoardSquare
功能,而不是使用DropTarget
中包装的功能。// Board.jsx
import {BoardSquare} from './BoardSquare.jsx';
// ^ ^ you are importing BoardSquare, not DropTarget(...)(BoardSquare)
应该是:
// Board.jsx
import BoardSquare from './BoardSquare.jsx';
因此,这意味着,由于您没有使用包装在
DropTarget
中的组件,因此没有人在调用collect
函数,因此也没有在设置connectDropTarget
道具。为了清理问题,您可以从
export
删除准系统类的BoardSquare
,而仅导出包装在DropTarget
中的类:// BoardSquare.jsx
export class BoardSquare extends Component {
// ^^^ remove this export statement