我开始从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

07-25 20:58