学习React DND时遇到的编译问题

Compilation problems while learning React DND

我开始从 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 的值15=] 通过 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 属性。

为了清理干净,您可以从 BoardSquare 中删除准系统 class 的 export,只导出包裹在 DropTarget 中的 class :

// BoardSquare.jsx
export class BoardSquare extends Component {
// ^^^ remove this export statement