React官网的井字棋游戏
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官网的井字棋游戏相关推荐
- Minimax 和 Alpha-beta 剪枝算法简介,及以此实现的井字棋游戏(Tic-tac-toe)
前段时间用 React 写了个2048 游戏来练练手,准备用来回顾下 React 相关的各种技术,以及试验一下新技术.在写这个2048的过程中,我考虑是否可以在其中加入一个 AI 算法来自动进行游戏, ...
- java——博弈算法实现井字棋游戏
通过java语言开发了一个简单的井字棋游戏.主要有6个类,其中有一个是主类(Main.java),一个是抽象类(PiecesMove.java)组成. 下面对各个类简单介绍一下: TicTicToe. ...
- python井字棋游戏代码_python实现井字棋游戏
python实现井字棋游戏 来源:中文源码网 浏览: 次 日期:2018年9月2日 [下载文档: python实现井字棋游戏.txt ] (友情提示:右键点上行txt文档名->目标 ...
- C语言第十课:编写井字棋游戏(综合练习1)
目录 前言: 一.文件建立: 1.头文件game.h: 2.函数定义文件game.c: 3.工程测试文件test.c: 二.编写井字棋游戏: 1.程序整体执行思路: 2.menu菜单函数实现: 3.g ...
- php井字游戏,python实现井字棋游戏
#本游戏python3.4.0下编写调试,只能在windows下运行. import random import subprocess import time #定义函数 def draw_board ...
- C++井字棋游戏,DOS界面版
据说有一个能保证不败的算法.明天看看先再写个PVC版的. 正题.今天无聊写了个井字棋游戏,顺便逐渐让自己习惯良好的代码风格,放上来给新手学习学习. jzq2.cpp /*N字棋游戏PVP版,DOS版本 ...
- python井字棋ai_[Python100行系列]-井字棋游戏
博客:Hzy的博客 | Hzy Bloghzeyuan.cn一些学习python的小项目,小游戏.python小项目github.com 话不多说,今天尝试用turtle库来写一个井字棋游戏.1. ...
- [CareerCup] 17.2 Tic Tac Toe 井字棋游戏
17.2 Design an algorithm to figure out if someone has won a game oftic-tac-toe. 这道题让我们判断玩家是否能赢井字棋游戏, ...
- 采用α-β算法实现井字棋游戏
题目描述 (1)图形化界面. (2)随机选取先手后手. (3)可以人-计算机或计算机-计算机 界面效果 算法 基本思想 Max-Min算法: 采用Max-Min算法进行对抗搜索,Max和Min双方均要 ...
最新文章
- WindowsServer2012史记7-茴香豆的五种写法和四种”显示计算机”的方法
- Python 通过ctypes调用 ICTCLAS3.0.DLL
- cnil在python_在Python中使用cumprod()计算权益曲线
- py导入包异常跳出_Python运行Unittest作为包导入错误
- 用offset调用文章
- python进阶与数据操控_零基础机器学习Python进阶:Python操作MySql
- 菜鸟学前端--javascript基础
- 【NOIP2016提高A组模拟10.15】打膈膜
- Kotlin入门(8)空值的判断与处理
- 使用谷歌语音识别打造语音管家HiVoice
- Flex 4中组件背景设置(填充方式)group为例子
- fastText:极快的文本分类工具
- 团队博客-第三周:需求改进系统设计(科利尔拉弗队)
- linux设计论文题目,计算机linux本科毕业论文题目
- win10下使用DuetDisplay有线/无线连接,推荐通过爱思助手(非iTunes)更新驱动
- SSD目标检测流程深入理解
- 在ubntu下安装Sublime text
- 省市区三级联动area
- 计算机管理没有指定运行,如何限制电脑只运行一个软件?只打开指定软件?
- Navicat Premium安装教程(激活)
热门文章
- 大学计算机专业哪个学校最好,计算机专业:最好的7所大学!也是全中国“最难考”的大学!...
- 网络安全绝地求生-面试题
- 学习ESP8266_11_系统软件定时器
- C语言程序设计-鸡兔同笼问题
- linux下qt软件使用方法,QT入门 QT Creator 使用
- 独立版旺店助手源码在线持续更新
- ADOBE pr000的下载安装+基本操作
- Keil用ST-LINK下载STM32程序后不自动运行
- 计算机硬盘改造u盘,iPhone扩容硬盘不要扔!变废为宝!手把手教你如何改装U盘...
- cesium three性能比较_希捷Exos 18TB跑分:容量大了和性能也高了点