井字棋的实现以及学习到的react实用技巧

教程大全  / 只看大图  / 倒序浏览   ©

#楼主# 2020-2-12

跳转到指定楼层

马上注册,分享更多源码,享用更多功能,让你轻松玩转云大陆。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

今天笔者来实习一个非常简单的功能,也就是大家都爱玩的井字棋,本次笔者参照了react官网的新手教程,会从0到1进行js代码的实现(css大家可以自己自由发挥)。个人认为这个例子帮助到了笔者很多,在做例子的时间遇到不会的地方都有看文档然后写对应的文章来进行记录

总结

总的来说这个让我学会了

  1. 组件的使用,分工要明确,使得维护就比力容易
  2. 数据为什么要传在最高级的父组件上
  3. key
  4. 不可变性
  5. state的具体用法
  6. props的流出

功能设想

  1. 点击后会瓜代出现X,O
  2. 汗青记录功能
  3. 优胜者判断
  4. 声明下一个棋子是X照旧O


    225033o7zmhx97bmtqdh48.png

手撕代码

开始写之前,我们要对整体项目有个大概的预估,大概需要哪几个组件?分别对应了什么功能?
笔者认为需要三个组件,一个用来渲染方格内的变革,一个用来渲染整体九宫格,一个用来存放游戏内部逻辑,因此我们可以整如下三个组件
组件A,Square

[	DISCUZ_CODE_0	]

组件B,board

[	DISCUZ_CODE_1	]

组件C,game

[	DISCUZ_CODE_2	]

简单搭构

建立好了组件,我们便可以对其中一些比力简单的功能进行实现和搭构,包括让每个方格都变成按钮可以接受变乱,渲染出九宫格,这里比力简单就不赘述了,其中css代码就不在这赘述

[	DISCUZ_CODE_3	]
225033om4z88yjyv6wwxyp.png

数据处理?

像新手都会本能有一个误区,认为数据在哪里显示渲染,数据就要存在哪里,实则这是一个非常错误的思想。笔者认为数据应该储存在内部逻辑中,也就是最高级的状态里,这样有几个好处

  1. 不消重复储存,假如仅仅存在最低级的状态中,每次其他更高级的状态要调用都要重新储存
  2. 假如写在底层的逻辑,固然代码是可行,但是每次维护修改都特殊的麻烦

以是不消想,应该把你的数据放在你最高级的父组件中,在这也就是Game组件,通常我们会使用构造函数去定义组件的属性

[	DISCUZ_CODE_4	]

在react中,组件中的 state 包含了随时大概发生变革的数据。state 由用户自定义,它是一个普通 JavaScript 对象。

假如某些值未用于渲染或数据流(例如,计时器 ID),则不必将其设置为 state。此类值可以在组件实例上定义。具体可以看我另外一篇文章state的具体用法

我们完成项目的思维应该是先一个一个完成功能,假如完成功能间会有冲突再进行更新修改
我们完成项目的思维应该是先一个一个完成功能,假如完成功能间会有冲突再进行更新修改
我们完成项目的思维应该是先一个一个完成功能,假如完成功能间会有冲突再进行更新修改

以是当我们需要确定数据的时间,我们来康康要完成第一个功能时,我们需要做什么?

点击后会瓜代出现X,O

我们要首先明白,点击后瓜代出现X,O是改变了什么?渲染的时间要渲染什么?然后每一个组件负责要做什么

其实比力清楚的是,square组件要做的就是接受父组件board组件通报出来的数据并且渲染出来,以是board组件要做的就是通报出合适的props给square渲染,相称于一个中间的过渡。而Game则是要通报出正确的逻辑给board组件,使其可以正确的传给square,因此两个子组件的写法就比力简单,先看board组件

[	DISCUZ_CODE_5	]

首先board要做的事情非常简单,game将会通报一个props给board,里面包含了要渲染的数据,同时也会通报一个关于onClick函数的props给它,以是它把这些给square就好了

[	DISCUZ_CODE_6	]

square组件渲染出board组件给的props就好

可以发现这样把数据存在父组件中,子组件的搭建就非常简单

接下来我们看看最难的game组件,要怎样做

[	DISCUZ_CODE_7	]

其实要做的有三个,一个是储存数据,一个是定义一个方法,然后是渲染时把board需要的props传出去

储存数据我们可以弄一个长度为9的空数组储存每次点击的数据,通过使用

  1. .slice()
复制代码
方法创建了数组的一个副本,而不是直接修改现有的数组。这是由于react中不可变性很重要。可以看看这篇关于不可变性的文章

然后整一个关于状态的属性来控制输出X照旧O
定义方法要做的就是每次点击会调用什么方法,来实现功能。这个很简单不赘述了,然后渲染出去就欧克了
然后把上面注释的地方改成传出去props的变量名就ok了

汗青记录功能

汗青记录功能其实最为要关注的就是game,因为子组件只需要渲染出给的东西就ok了,以是不消怎么变动

因为要记录汗青,以是我们要先对储存数据增加一个history的属性,同时还要把走到第几步记下来。

[	DISCUZ_CODE_9	]

以是我们改变了构造函数成了这样,其实逻辑就是让history不止记下一次的操作和值,会每次都改变原来的history数组,以是我们背面也选择了concat方法而不是push,正是这个原因。
然后我们康康方法的变革
首先是原来的handleClick方法

[	DISCUZ_CODE_10	]

遵从数据的不可变性,我们声明白一个新的history来记录从开始到进行的这一步,这个方法的变革逻辑也很好理解看看码就行了

然后是jumpto的方法

[	DISCUZ_CODE_11	]

实际上就是改变stepNumber使得回到那一步
最后是渲染

[	DISCUZ_CODE_12	]

这里需要重点提一下的是

  1. <li key={move}>
复制代码
,key的重要性可以去看看我的文章key
,什么时间要用什么时间不消为什么要用都讲的很清楚了。
其实相对而言其他逻辑都比力简单就不赘述了

优胜者判断

这里要整一个判断的函数

[	DISCUZ_CODE_14	]

实际上这个判断逻辑也很容易,就是把获胜大概性列出来,然后判断存不存在即可。
其他的就是把源码补充一下就好
井字棋源码

分享淘帖
回复

使用道具

您的回复是对作者最大的奖励

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于作者

好好的_cd76

新手猿

  • 主题

    11

  • 帖子

    11

  • 关注者

    0

Archiver|手机版|小黑屋|云大陆 | 赣ICP备18008958号-4|网站地图
Powered by vrarz.com!  © 2019-2020版权所有云大陆