{"id":16753394,"url":"https://github.com/kaynewang/react-dnd-chessboard","last_synced_at":"2026-04-17T03:03:46.861Z","repository":{"id":143951503,"uuid":"124362677","full_name":"KayneWang/react-dnd-Chessboard","owner":"KayneWang","description":"根据react-dnd文档，实现其中棋盘拖动demo","archived":false,"fork":false,"pushed_at":"2018-03-13T10:34:47.000Z","size":24,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-16T05:41:20.886Z","etag":null,"topics":["react","react-dnd","webpack"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KayneWang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-08T08:43:08.000Z","updated_at":"2021-09-23T12:32:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"2336764b-15b9-4a32-a982-e376e2b2b027","html_url":"https://github.com/KayneWang/react-dnd-Chessboard","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/KayneWang/react-dnd-Chessboard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KayneWang%2Freact-dnd-Chessboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KayneWang%2Freact-dnd-Chessboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KayneWang%2Freact-dnd-Chessboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KayneWang%2Freact-dnd-Chessboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KayneWang","download_url":"https://codeload.github.com/KayneWang/react-dnd-Chessboard/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KayneWang%2Freact-dnd-Chessboard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31913078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T18:22:33.417Z","status":"online","status_checked_at":"2026-04-17T02:00:06.879Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","react-dnd","webpack"],"created_at":"2024-10-13T02:49:58.507Z","updated_at":"2026-04-17T03:03:46.840Z","avatar_url":"https://github.com/KayneWang.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## 本地开发\n\n```shell\n$ git clone https://github.com/wangzengkai/react-dnd-Chessboard.git\n$ npm install\n$ npm start\n```\n\n## react-dnd棋盘实现\n方便快速理解react-dnd，官方提供了Chessboard例子，本项目是对官方例子的具体实现，为了方便初学者快速入手接下来笔者将会使用一些通俗易懂的表达方式一步一步完成此例子的开发。当然，您也可以访问[react-dnd文档](http://react-dnd.github.io/react-dnd/docs-tutorial.html)进行开发。\n\u003cbr /\u003e\n\n在开发过程中，笔者使用的是es6，如果不了解的话，可以参考阮一峰老师的[ECMAScript 6 入门](http://es6.ruanyifeng.com/)\n\n## 环境准备\n用户可以自行使用webpack搭建react的基础开发环境，这里推荐阅读[从零搭建React全家桶框架教程](https://github.com/brickspert/blog/issues/1)，当然也可以使用笔者自己使用的[react-webpack-boilerplate](https://github.com/wangzengkai/react-webpack-boilerplate)来快速开始。\n\n## 确认组件\n就像大多数开发一样，我们开发之前要大概确定一下所需要的组件，这里不绕弯子，直接按照文档所说，我们大概将组件分为以下三个：\n\n- Knight，其中可以拖动的骑士组件\n- Square，棋盘中的一个方块组件\n- Board，整个棋盘面板，包含64个方块\n\n思考一下组件是否需要props\n\n- Knight不需要props，因为它在棋盘中肯定会作为Square的子组件\n- Square中我们可以通过使用props来控制所在位置，但是这次我们并不需要，我们只需要Square来控制渲染颜色，因为棋盘是通过黑白两种颜色组成，当然Square会接收一个子组件\n- Board比较麻烦，这里笔者感觉介绍太多并无太大作用，还是通过后续开发过程中来完善（主要是文档说了一堆考虑的问题，我不想在这个快速上手的文档中作介绍了，偷个懒）\n\n## 开始开发\n\n首先我们在src文件夹下面（如果没有src，请在根目录创建）创建components文件夹。\n\u003cbr /\u003e\n\n在components中创建Knight.js\n\n```js\nimport React from 'react'\n\nexport default class Knight extends React.Component {\n    render() {\n        return \u003cspan\u003e♘\u003c/span\u003e\n    }\n}\n```\n\n接下来我们修改[react-webpack-boilerplate](https://github.com/wangzengkai/react-webpack-boilerplate)生成的src/index.js文件\n\n```js\nimport React from 'react'\nimport ReactDom from 'react-dom'\nimport Knight from './components/Knight'\n\nReactDom.render(\u003cKnight /\u003e, document.getElementById('app'))\n```\n\n然后我们就能看到如下效果：\n![image](http://i.imgur.com/NktjTMn.png)\n\n接下来我们要开始开发Square组件了，在src/components中创建Square.js\n\n```js\nimport React from 'react'\nimport PropTypes from 'prop-types'\n\nexport default class Square extends React.Component {\n    render() {\n        const { black } = this.props\n        const fill = black ? 'black' : 'white'\n        const stroke = black ? 'white' : 'black'\n        \n        return (\n            \u003cdiv\n                style={{\n                    backgroundColor: fill,\n                    color: stroke,\n                    width: '100%',\n                    height: 50\n                }}\n            \u003e\n                {this.props.children}\n            \u003c/div\u003e\n        )\n    }\n}\n\nSquare.propTypes = {\n    black: PropTypes.bool\n}\n```\n\n接下来我们修改src/index.js\n```js\nimport React from 'react'\nimport ReactDom from 'react-dom'\nimport Knight from './components/Knight'\nimport Square from './components/Square'\n\nReactDom.render(\n    \u003cSquare black\u003e\n        \u003cKnight /\u003e\n    \u003c/Square\u003e,\n    document.getElementById('app')\n)\n```\n然后可以看到如下效果（忽略高度，因为笔者这里设置的是50）：\n![image](http://i.imgur.com/jvgv6DV.png)\n\n最后，我们开始开发Board组件，在src/components中创建Board.js\n```js\nimport React from 'react'\nimport PropTypes from 'prop-types'\nimport Square from './Square'\nimport Knight from './Knight'\n\nexport default class Board extends React.Component {\n    render() {\n        return (\n            \u003cdiv\u003e\n                \u003cSquare black\u003e\n                    \u003cKnight /\u003e\n                \u003c/Square\u003e\n            \u003c/div\u003e\n        )\n    }\n}\n\nBoard.propTypes = {\n    knightPosition: PropTypes.arrayOf(\n        PropTypes.number.isRequired\n    ).isRequired\n}\n```\n\n修改src/index.js\n```js\nimport React from 'react'\nimport ReactDom from 'react-dom'\nimport Board from './components/Board'\n\nReactDom.render(\n    \u003cBoard knightPosition={[0, 0]} /\u003e,\n    document.getElementById('app')\n)\n```\n\n下面，我们第一次尝试开发renderSquare方法，在src/components/Board.js中添加\n```js\nrenderSquare(x, y) {\n    const black = (x + y) % 2 === 1\n    \n    const [knightX, knightY] = this.props.knightPosition\n    const piece = (x === knightX \u0026\u0026 y === knightY) ? \u003cKnight /\u003e : null\n    \n    return (\n        \u003cSquare black={black}\u003e\n            {piece}\n        \u003c/Square\u003e\n    )\n}\n```\n改变Board中的render方法看一下效果\n```js\nrender() {\n    return (\n        \u003cdiv\u003e\n            {this.renderSquare(0, 0)}\n            {this.renderSquare(1, 0)}\n            {this.renderSquare(2, 0)}\n        \u003c/div\u003e\n    )\n}\n```\n下面我们优化一下代码，给我们的Board加上样式，同时遍历出64块Square\n```js\nimport React from 'react'\nimport PropTypes from 'prop-types'\nimport Square from './Square'\nimport Knight from './Knight'\n\nexport default class Board extends React.Component {\n    renderSquare(i) {\n        const x = i % 8\n        const y = Math.floor(i / 8)\n        const black = (x + y) % 2 === 1\n        \n        const [knightX, knightY] = this.props.knightPosition\n        const piece = (x === knightX \u0026\u0026 y === knightY) ? \u003cKnight /\u003e : null\n        \n        return (\n            \u003cdiv key={i} style={{ width: '12.5%', height: '12.5%' }}\u003e\n                \u003cSquare black={black}\u003e\n                    {piece}\n                \u003c/Square\u003e\n            \u003c/div\u003e\n        )\n    }\n    \n    render() {\n        const squares = []\n        for (let i = 0; i \u003c 64; i++) {\n            squares.push(this.renderSquare(i))\n        }\n        \n        return (\n            \u003cdiv style={{ display: 'flex', flexWrap: 'wrap', width: 400 }}\u003e\n                {squares}\n            \u003c/div\u003e\n        )\n    }\n}\n\nBoard.propTypes = {\n  knightPosition: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired\n}\n```\n\n完成之后你应该可以看到如下效果了\n![image](http://i.imgur.com/RsQDI4Y.png)\n\n现在看起来好多了，我们尝试修改一下src/index.js中传递的knightPosition属性\n\n```js\nimport React from 'react'\nimport ReactDom from 'react-dom'\nimport Board from './components/Board'\n\nReactDom.render(\n    \u003cBoard knightPosition={[7, 4]} /\u003e,\n    document.getElementById('app')\n)\n```\n\n![image](http://i.imgur.com/0fNBn5a.png)\n\n## 添加状态\n\n文档作者在这里提到希望通过通过一个文件来控制KnightPosition，实际开发中的做法是使用Flux、Redux等，这里我们根据作者文档实现一个Game来改变我们的KnightPosition，首先改写src/index.js\n\n```js\nimport React from 'react'\nimport ReactDom from 'react-dom'\nimport Board from './components/Board'\nimport { observe } from './components/Game'\n\nconst rootEl = document.getElementById('app')\n\nobserve(knightPosition =\u003e ReactDom.render(\u003cBoard knightPosition={knightPosition} /\u003e, rootEl))\n```\n\n接下来我们先实现一个初始版的Game，在src/components中创建Game.js文件\n\n```js\nexport function observe(receive) {\n    setInterval(() =\u003e receive([\n        Math.floor(Math.random() * 8),\n        Math.floor(Math.random() * 8)\n    ]), 500)\n}\n```\n\n现在我们可以看到\n\n![image](https://s3.amazonaws.com/f.cl.ly/items/1K0s0n0r0C0e2P2N2D1d/Screen%20Recording%202015-05-15%20at%2012.06%20pm.gif)\n\n修改src/components/Game.js\n\n```js\nlet knightPosition = [0, 0]\nlet observer = null\n\nfunction emitChange() {\n    observer(knightPosition)\n}\n\nexport function observe(o) {\n    if (observer) {\n        throw new Error('Multiple observers not implemented.')\n    }\n    observer = o\n    emitChange()\n}\n\nexport function moveKnight(toX, toY) {\n    knightPosition = [toX, toY]\n    emitChange()\n}\n```\n\n现在，我们回到组件中，我们的目标是通过点击方块来移动Knight。作者这里提到了为什么使用Board来控制位置的原因（大概意思就是Square不需要确定自己的位置来渲染），修改src/components/Board.js，增加代码\n\n```js\nimport React from 'react'\nimport PropTypes from 'prop-types'\nimport Square from './Square'\nimport Knight from './Knight'\nimport { moveKnight } from './Game'\n\n/* 其它代码 */\n\nrenderSquare(i) {\n  const x = i % 8\n  const y = Math.floor(i / 8)\n  const black = (x + y) % 2 === 1\n\n  const [knightX, knightY] = this.props.knightPosition\n  const piece = (x === knightX \u0026\u0026 y === knightY) ?\n    \u003cKnight /\u003e :\n    null\n\n  return (\n    \u003cdiv key={i}\n         style={{ width: '12.5%', height: '12.5%' }}\n         onClick={() =\u003e this.handleSquareClick(x, y)}\u003e\n      \u003cSquare black={black}\u003e\n        {piece}\n      \u003c/Square\u003e\n    \u003c/div\u003e\n  );\n}\n\nhandleSquareClick(toX, toY) {\n  moveKnight(toX, toY)\n}\n```\n\n接下来我们需要定义一个移动规则，在src/components/Game.js中新增\n\n```js\nlet knightPosition = [1, 7]\n\n/* 其它代码 */\n\nexport function canMoveKnight(toX, toY) {\n  const [x, y] = knightPosition;\n  const dx = toX - x\n  const dy = toY - y\n\n  return (Math.abs(dx) === 2 \u0026\u0026 Math.abs(dy) === 1) ||\n         (Math.abs(dx) === 1 \u0026\u0026 Math.abs(dy) === 2)\n}\n```\n\n最后，修改src/components/Board.js\n\n```js\nimport { canMoveKnight, moveKnight } from './Game'\n\n/* 其它代码 */\n\nhandleSquareClick(toX, toY) {\n  if (canMoveKnight(toX, toY)) {\n    moveKnight(toX, toY)\n  }\n}\n```\n\n![image](https://s3.amazonaws.com/f.cl.ly/items/1F371u301l1H2X3o0g1h/Screen%20Recording%202015-05-15%20at%2012.08%20pm.gif)\n\n## 添加拖拽交互\n\n下面我们将看到如何使用React DnD来实现组件的拖拽功能\n\n```shell\n$ npm install --save react-dnd react-dnd-html5-backend\n```\n\n首先我们要设置DragDropContext，并且指定在应用中使用HTML5 backend\n\n修改src/components/Board.js\n\n```js\nimport React, { Component } from 'react'\nimport { DragDropContext } from 'react-dnd'\nimport HTML5Backend from 'react-dnd-html5-backend'\n\nclass Board extends Component {\n  /* 其它代码 */\n}\n\nexport default DragDropContext(HTML5Backend)(Board)\n```\n\n然后，在src/components创建constants.js\n\n```js\nexport const ItemTypes = {\n  KNIGHT: 'knight'\n}\n```\n\nDragSource高阶组件接受三个参数：type,spec,collect。本例中我们使用constants中定义的，所以我们现在需要开发drag source的规范和collecting方法。修改src/components/Knight.js，新增\n\n```js\nconst knightSource = {\n  beginDrag(props) {\n    return {}\n  }\n}\n```\n\n因为我们这里没有需要描述的：在整个拖动应用中实际只有一个拖动对象。如果我们有很多棋子，我们就可以使用props参数来返回例如{pieceId: props.id}。在该例子中，空对象就可以满足条件了。\n\n接下来我们需要开发collecting方法，用于返回Knight所需要的属性。我们必须得确定拖动源节点，或者我们可以调整拖动过程中的透明度等等。所以，我们需要知道当前节点是否正在被拖动。\n\n修改src/components/Knight.js，新增\n\n```js\nfunction collect(connect, monitor) {\n  return {\n    connectDragSource: connect.dragSource(),\n    isDragging: monitor.isDragging()\n  }\n}\n```\n\n现在，我们整体看一下Knight组件\n\n```js\nimport React from 'react'\nimport PropTypes from 'prop-types'\nimport { ItemTypes } from './Constants'\nimport { DragSource } from 'react-dnd'\n\nconst knightSource = {\n  beginDrag(props) {\n    return {}\n  }\n}\n\nfunction collect(connect, monitor) {\n  return {\n    connectDragSource: connect.dragSource(),\n    isDragging: monitor.isDragging()\n  }\n}\n\nclass Knight extends React.Component {\n  render() {\n    const { connectDragSource, isDragging } = this.props\n    return connectDragSource(\n      \u003cdiv style={{ opacity: isDragging ? 0.5 : 1, fontSize: 25, fontWeight: 'bold', cursor: 'move' }}\u003e\n        ♘\n      \u003c/div\u003e\n    )\n  }\n}\n\nKnight.propTypes = {\n  connectDragSource: PropTypes.func.isRequired,\n  isDragging: PropTypes.bool.isRequired\n}\n\nexport default DragSource(ItemTypes.KNIGHT, knightSource, collect)(Knight)\n```\n\n![image](https://s3.amazonaws.com/f.cl.ly/items/3L1d0C203C0s1r1H2H0m/Screen%20Recording%202015-05-15%20at%2001.11%20pm.gif)\n\n现在Kinght已经是拖动源了，只是我们目前还没有放置目标。下面我们开始开发Square为放置目标。\n\n这次，我们需要进行组件拆分了，具体原因作者文档描述的很详细，我们直接进行拆分。\n\n在src/components中创建BoardSquare.js\n\n```js\nimport React, { Component } from 'react'\nimport PropTypes from 'prop-types'\nimport Square from './Square'\n\nexport default class BoardSquare extends Component {\n  render() {\n    const { x, y } = this.props\n    const black = (x + y) % 2 === 1\n\n    return (\n      \u003cSquare black={black}\u003e\n        {this.props.children}\n      \u003c/Square\u003e\n    )\n  }\n}\n\nBoardSquare.propTypes = {\n  x: PropTypes.number.isRequired,\n  y: PropTypes.number.isRequired\n}\n```\n\n修改src/components/Board.js\n\n```js\nrenderSquare(i) {\n  const x = i % 8\n  const y = Math.floor(i / 8)\n  return (\n    \u003cdiv key={i}\n         style={{ width: '12.5%', height: '12.5%' }}\u003e\n      \u003cBoardSquare x={x}\n                   y={y}\u003e\n        {this.renderPiece(x, y)}\n      \u003c/BoardSquare\u003e\n    \u003c/div\u003e\n  )\n}\n\nrenderPiece(x, y) {\n  const [knightX, knightY] = this.props.knightPosition\n  if (x === knightX \u0026\u0026 y === knightY) {\n    return \u003cKnight /\u003e\n  }\n}\n```\n\n现在使用DropTarget封装BoardSquare，这里只写了一个放置目标规范的drop事件，修改src/components/BoardSquare.js，新增\n\n```js\nconst squareTarget = {\n  drop(props, monitor) {\n    moveKnight(props.x, props.y)\n  }\n}\n```\n\n这里我们看到drop方法可以接受props，所以我们可以知道Knight是从那个位置移动过来的。在实际开发中，有可能会用到monitor.getItem()去检索从beginDrag返回的拖拽详情。\n\n在collecting方法中，我们将获取连接放置目标节点的功能，并且我们可以通过monitor知道鼠标是否在当前BoardSquare中，这样我们才可以突出显示\n\n```js\nfunction collect(connect, monitor) {\n  return {\n    connectDropTarget: connect.dropTarget(),\n    isOver: monitor.isOver()\n  }\n}\n```\n\n修改BoardSquare\n\n```js\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport Square from './Square';\nimport { canMoveKnight, moveKnight } from './Game';\nimport { ItemTypes } from './Constants';\nimport { DropTarget } from 'react-dnd';\n\nconst squareTarget = {\n  drop(props) {\n    moveKnight(props.x, props.y);\n  }\n};\n\nfunction collect(connect, monitor) {\n  return {\n    connectDropTarget: connect.dropTarget(),\n    isOver: monitor.isOver()\n  };\n}\n\nclass BoardSquare extends Component {\n  render() {\n    const { x, y, connectDropTarget, isOver } = this.props;\n    const black = (x + y) % 2 === 1;\n\n    return connectDropTarget(\n      \u003cdiv style={{\n        position: 'relative',\n        width: '100%',\n        height: '100%'\n      }}\u003e\n        \u003cSquare black={black}\u003e\n          {this.props.children}\n        \u003c/Square\u003e\n        {isOver \u0026\u0026\n          \u003cdiv style={{\n            position: 'absolute',\n            top: 0,\n            left: 0,\n            height: '100%',\n            width: '100%',\n            zIndex: 1,\n            opacity: 0.5,\n            backgroundColor: 'yellow',\n          }} /\u003e\n        }\n      \u003c/div\u003e\n    );\n  }\n}\n\nBoardSquare.propTypes = {\n  x: PropTypes.number.isRequired,\n  y: PropTypes.number.isRequired,\n  connectDropTarget: PropTypes.func.isRequired,\n  isOver: PropTypes.bool.isRequired\n};\n\nexport default DropTarget(ItemTypes.KNIGHT, squareTarget, collect)(BoardSquare);\n```\n\n![image](https://s3.amazonaws.com/f.cl.ly/items/2U43301g421U3I2X2p0P/Screen%20Recording%202015-05-15%20at%2001.55%20pm.gif)\n\n修改src/components/BoardSquare.js中的squareTarget对象，新增canDrop\n\n```js\nconst squareTarget = {\n  canDrop(props) {\n    return canMoveKnight(props.x, props.y)\n  },\n\n  drop(props, monitor) {\n    moveKnight(props.x, props.y)\n  }\n}\n```\n\n我们还需要在collecting方法中添加monitor.canDrop()，并且添加一些代码渲染效果\n\n```js\nimport React from 'react'\nimport PropTypes from 'prop-types'\nimport Square from './Square'\nimport { moveKnight, canMoveKnight } from './Game'\nimport { ItemTypes } from './Constants'\nimport { DropTarget } from 'react-dnd'\n\nconst squareTarget = {\n  canDrop(props) {\n    return canMoveKnight(props.x, props.y)\n  },\n\n  drop(props, monitor) {\n    moveKnight(props.x, props.y)\n  }\n}\n\nfunction collect(connect, monitor) {\n  return {\n    connectDropTarget: connect.dropTarget(),\n    isOver: monitor.isOver(),\n    canDrop: monitor.canDrop()\n  }\n}\n\nclass BoardSquare extends React.Component {\n  renderOverlay(color) {\n    return (\n      \u003cdiv\n        style={{ position: 'absolute', top: 0, left: 0, height: '100%', width: '100%', zIndex: 1, opacity: 0.5, backgroundColor: color }}\n      /\u003e\n    )\n  }\n  render() {\n    const { x, y, connectDropTarget, isOver, canDrop } = this.props\n    const black = (x + y) % 2 === 1\n    return (\n      connectDropTarget(\n        \u003cdiv style={{ position: 'relative', width: '100%', height: '100%' }}\u003e\n          \u003cSquare black={black}\u003e\n            {this.props.children}\n          \u003c/Square\u003e\n          {isOver \u0026\u0026 !canDrop \u0026\u0026 this.renderOverlay('red')}\n          {!isOver \u0026\u0026 canDrop \u0026\u0026 this.renderOverlay('yellow')}\n          {isOver \u0026\u0026 canDrop \u0026\u0026 this.renderOverlay('green')}\n        \u003c/div\u003e\n      )\n    )\n  }\n}\n\nBoardSquare.propTypes = {\n  x: PropTypes.number.isRequired,\n  y: PropTypes.number.isRequired,\n  connectDropTarget: PropTypes.func.isRequired,\n  isOver: PropTypes.bool.isRequired,\n  canDrop: PropTypes.bool.isRequired\n}\n\nexport default DropTarget(ItemTypes.KNIGHT, squareTarget, collect)(BoardSquare)\n```\n\n![image](https://s3.amazonaws.com/f.cl.ly/items/0X3c342g0i3u100p1o18/Screen%20Recording%202015-05-15%20at%2002.05%20pm.gif)\n\n这样，我们的拖拽例子已经完成了\n\n## 最后触发优化\n\n可以参考[原文档](http://react-dnd.github.io/react-dnd/docs-tutorial.html)进行修改。\n\n\n\u003cbr /\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaynewang%2Freact-dnd-chessboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaynewang%2Freact-dnd-chessboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaynewang%2Freact-dnd-chessboard/lists"}