React官网的井字棋游戏

这个是我在官网再次复习这个小游戏时梳理的一些思路,其中也包含了我在尝试时出的一些bug

文章目录

  • React官网的井字棋游戏
    • 1.整体分析项目
    • 2.为变量添加state并绑定点击事件
    • 3.轮流落子
    • 4.判断输赢
    • 5.时间旅行
    • 6.展示历史步骤
    • 7.总结
1.整体分析项目

先对整个项目进行分析,可以分割为哪些组件,组件之间应该如何联系

这个小游戏中一共分为三个组件

Square组件:用来渲染每一个小方格

Board组件:控制九个方格这一面板

Game组件:控制更宏观的东西

可以通过初步的分析设计出这三个组件,以及确定好组件之间的关系

可以先由此写出一个没有交互,没有变化的静态页面

2.为变量添加state并绑定点击事件

接下来为这个项目添加"活力"

1.Square组件需要实时打印’X’、'Y’或空白,是变化量,因此要设置为state可以修改

2.但是在这个游戏中,需要判断输赢,单独的九个Square无法关联,因此需要状态提升

将这个value设置值为Board的State,再通过参数Props传入Square,就能实现在Board层面,宏观控制九个值的关系,判断输赢

  constructor(props){super(props);this.state={squares: Array(9).fill(null),}}

在Board组件中声明

3.根据用户的点击,要在棋盘上落子,因此要响应onClick事件

但是,onClick是直接与Square的botton相关联,而state在Board中

直接的onClick处理函数无法越级更改父级中的State

因此,onClick事件的处理一定要在Board组件中

所以,可以在Square中额外添加一个onClick属性,由父组件的props传入,这样在点击时就会调用Board里的处理函数

value的值也与onClick一样由Board传入

相当于这个点击事件的状态也随之提升了

Square组件也被称为受控组件,完全由Board进行控制

4.下面需要完善Board里的点击事件处理函数

    handleClick(i){const squares =this.state.squares.slice();squares[i]='X';this.setState({squares: squares,})}

需要注意的是,在这里,我们用新的一份数据来替换旧的数据,这样比直接修改数据有一些好处

如果直接进行修改的话,很难追踪到数据的改变,而用整体替换,相当于有很多的历史版本,对于数据维护,或者是撤销等复杂功能提供了更好的实现方法。

写完之后点击会在相应的方格出现’X’

但是我在这里犯了两个小错误:

在这里,应该传递的是数字这个索引,而不是直接传递

如果传递数字的话,它就像一个Id,有很高的复用性,但是值得复用性就很低

因此要把8也改为this.renderSquare(8) (前几个我已经改回来了)

然后运行后点击还是没有反应,对比代码后发现,传入的onClick必须加括号

可能因为onClick的值是一段js代码,所以被理解为了函数

修改完之后就可以正常运行了

5.由于Square只有一个render方法,可以改写成函数组件,更方便一些

像这样:

  function Square(props){return(<button className="square" onClick={props.onClick()}>{props.value}</button>);}

但是之后又又又报错了,,找了半天才发现改为函数组件后,要去掉后面的括号

这样才是对的

3.轮流落子

在这里需要在state中额外添加一个变量来储存,下一位应该是哪个玩家/改玩家能不能落子


这个地方要写圆括号,写大括号会报错

4.判断输赢

要写一个能判断输赢的全局函数

  function calculateWinner(squares){const lines=[[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6],];for(let i=0;i<lines.length;i++){const [a,b,c]=lines[i];if(squares[a]&&squares[a]===squares[b]&&squares[a]===squares[c]){return squares[a];}}return null;}

要防止用户多次点击,或者在决出胜者之后,不能再落子

一个类组件一般包含几部分

第一部分一般写构造函数、事件处理函数等等

第二部分一般写一些逻辑代码

第三步部分return内的,代表想在页面上展示的

5.时间旅行

实现时间回溯的功能,与之前的squares.slice()处理有很大的关系

用这种切片的处理,让数据追踪变得容易,每一次都是静态不变的历史数据版本,只要再声明一个history将其储存下来即可

我们想用最外层的game组件实现这一部分,因此history应声明在history的state中,同时要将board组件里的squares状态再次梯提升,这样history就能直接与其操作了

注意大括号

用Array声明相当于执行了js代码,所以要套在大括号里

修改后的点击事件处理函数

6.展示历史步骤

在处理未知个数据时,可以用map方法,把它们一个个都渲染出来

写成move元素的形式,然后再在最下面调用即可

比直接写在下面要好得多

在构建动态列表时,要指定一个合适的key

系统会根据key查找上次与其相同的元素,进行比较,然后重新渲染

最后引入一个state参数,stepNumber,来记录版本号,这样处理会更方便一些

两个核心函数:

所有代码:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';function Square(props){return(<button className="square" onClick={props.onClick}>{props.value}</button>);}class Board extends React.Component {renderSquare(i) {return (<Squarevalue={this.props.squares[i]}onClick={()=>this.props.onClick(i)}/> )}render() {return (<div><div className="board-row">{this.renderSquare(0)}{this.renderSquare(1)}{this.renderSquare(2)}</div><div className="board-row">{this.renderSquare(3)}{this.renderSquare(4)}{this.renderSquare(5)}</div><div className="board-row">{this.renderSquare(6)}{this.renderSquare(7)}{this.renderSquare(8)}</div></div>);}}class Game extends React.Component {constructor(props){super(props);this.state={history: [{squares: Array(9).fill(null)},],xIsNext: true,stepNumber: 0,}}handleClick(i){const history=this.state.history.slice(0,this.state.stepNumber+1);const current=history[history.length-1];const squares=current.squares.slice();if(squares[i]||calculateWinner(squares)){return;}squares[i]=this.state.xIsNext?'X':'O';this.setState({history: history.concat([{squares: squares,}]),xIsNext: !this.state.xIsNext,stepNumber: history.length,});}jumpTo(step){this.setState({stepNumber: step,xIsNext: (step%2)===0,})}render() {const history=this.state.history;const current=history[this.state.stepNumber];const winner=calculateWinner(current.squares);const moves=history.map((step,move)=>{const desc=move?'Go to move #'+move:'Go to game start';return(<li key={move}><botton onClick={()=>this.jumpTo(move)}>{desc}</botton></li>)})let status;if(winner){status='Winner: '+ winner;}else{status='Next Player: '+(this.state.xIsNext?'X':'O');}return (<div className="game"><div className="game-board"><Board squares={current.squares}onClick={(i)=>this.handleClick(i)}/></div><div className="game-info"><div>{ status }</div><ol>{moves}</ol></div></div>);}}// ========================================const root = ReactDOM.createRoot(document.getElementById("root"));root.render(<Game />);function calculateWinner(squares){const lines=[[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6],];for(let i=0;i<lines.length;i++){const [a,b,c]=lines[i];if(squares[a]&&squares[a]===squares[b]&&squares[a]===squares[c]){return squares[a];}}return null;}

效果:

7.总结

在学习技术的时候,永远是要勤写,光停留在理论层面是学不会的,在自己敲代码的时候,能留意到更多的细节,也会引发更多的思考,同时也会加深对这个项目的理解,也能积累下来很多代码的经验

在写代码的过程中要仔细,一个小小的错误可能会为找bug带来巨大的苦恼,所以尽量不犯小错误,能减少bug的出现,保护头发

在IT行业,一方面技术更新迭代很快,另一方面确实感受到知识面很广,要学很多的东西,了解很多的东西,还是要多学多看多了解,慢慢积累

在前端项目中,尤其是大型项目,一般要使用React+Axios,

简单的项目一般使用jQuary+$.ajax就可以了

当然前端也有使用很广泛的Vue框架,这个等之后有空再学

复习到这里,基本上也算复习完了,在暑期实训的同时,要把axios学了,再学一学与后端对接的知识

加油!!

React官网的井字棋游戏相关推荐

  1. Minimax 和 Alpha-beta 剪枝算法简介,及以此实现的井字棋游戏(Tic-tac-toe)

    前段时间用 React 写了个2048 游戏来练练手,准备用来回顾下 React 相关的各种技术,以及试验一下新技术.在写这个2048的过程中,我考虑是否可以在其中加入一个 AI 算法来自动进行游戏, ...

  2. java——博弈算法实现井字棋游戏

    通过java语言开发了一个简单的井字棋游戏.主要有6个类,其中有一个是主类(Main.java),一个是抽象类(PiecesMove.java)组成. 下面对各个类简单介绍一下: TicTicToe. ...

  3. python井字棋游戏代码_python实现井字棋游戏

    python实现井字棋游戏 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  python实现井字棋游戏.txt ] (友情提示:右键点上行txt文档名->目标 ...

  4. C语言第十课:编写井字棋游戏(综合练习1)

    目录 前言: 一.文件建立: 1.头文件game.h: 2.函数定义文件game.c: 3.工程测试文件test.c: 二.编写井字棋游戏: 1.程序整体执行思路: 2.menu菜单函数实现: 3.g ...

  5. php井字游戏,python实现井字棋游戏

    #本游戏python3.4.0下编写调试,只能在windows下运行. import random import subprocess import time #定义函数 def draw_board ...

  6. C++井字棋游戏,DOS界面版

    据说有一个能保证不败的算法.明天看看先再写个PVC版的. 正题.今天无聊写了个井字棋游戏,顺便逐渐让自己习惯良好的代码风格,放上来给新手学习学习. jzq2.cpp /*N字棋游戏PVP版,DOS版本 ...

  7. python井字棋ai_[Python100行系列]-井字棋游戏

    博客:Hzy的博客 | Hzy Blog​hzeyuan.cn一些学习python的小项目,小游戏.python小项目​github.com 话不多说,今天尝试用turtle库来写一个井字棋游戏.1. ...

  8. [CareerCup] 17.2 Tic Tac Toe 井字棋游戏

    17.2 Design an algorithm to figure out if someone has won a game oftic-tac-toe. 这道题让我们判断玩家是否能赢井字棋游戏, ...

  9. 采用α-β算法实现井字棋游戏

    题目描述 (1)图形化界面. (2)随机选取先手后手. (3)可以人-计算机或计算机-计算机 界面效果 算法 基本思想 Max-Min算法: 采用Max-Min算法进行对抗搜索,Max和Min双方均要 ...

最新文章

  1. WindowsServer2012史记7-茴香豆的五种写法和四种”显示计算机”的方法
  2. Python 通过ctypes调用 ICTCLAS3.0.DLL
  3. cnil在python_在Python中使用cumprod()计算权益曲线
  4. py导入包异常跳出_Python运行Unittest作为包导入错误
  5. 用offset调用文章
  6. python进阶与数据操控_零基础机器学习Python进阶:Python操作MySql
  7. 菜鸟学前端--javascript基础
  8. 【NOIP2016提高A组模拟10.15】打膈膜
  9. Kotlin入门(8)空值的判断与处理
  10. 使用谷歌语音识别打造语音管家HiVoice
  11. Flex 4中组件背景设置(填充方式)group为例子
  12. fastText:极快的文本分类工具
  13. 团队博客-第三周:需求改进系统设计(科利尔拉弗队)
  14. linux设计论文题目,计算机linux本科毕业论文题目
  15. win10下使用DuetDisplay有线/无线连接,推荐通过爱思助手(非iTunes)更新驱动
  16. SSD目标检测流程深入理解
  17. 在ubntu下安装Sublime text
  18. 省市区三级联动area
  19. 计算机管理没有指定运行,如何限制电脑只运行一个软件?只打开指定软件?
  20. Navicat Premium安装教程(激活)

热门文章

  1. 大学计算机专业哪个学校最好,计算机专业:最好的7所大学!也是全中国“最难考”的大学!...
  2. 网络安全绝地求生-面试题
  3. 学习ESP8266_11_系统软件定时器
  4. C语言程序设计-鸡兔同笼问题
  5. linux下qt软件使用方法,QT入门 QT Creator 使用
  6. 独立版旺店助手源码在线持续更新
  7. ADOBE pr000的下载安装+基本操作
  8. Keil用ST-LINK下载STM32程序后不自动运行
  9. 计算机硬盘改造u盘,iPhone扩容硬盘不要扔!变废为宝!手把手教你如何改装U盘...
  10. cesium three性能比较_希捷Exos 18TB跑分:容量大了和性能也高了点