初识React(一)从井字棋游戏开始

写在前面:

磨磨唧唧了好久终于下定决心开始学react,刚刚接触感觉有点无从下脚...新的语法新的格式跟vue就像两种物种...倒是很好奇路由和store是怎么实现的了~v~,一点一点来吧!!!

(一)创建项目

使用vite创建

npm create vite

选择react项目,欧啦现在开始:

main.tsx文件:

还是熟悉的味道,鉴于我还搞不清楚组件和路由,就直接在app.tsx里面开干

(二)制作井字棋游戏 

1. 搭建九宫格形状

(1)用Square组件实现小格子

function Square() {return (<><button className='square'>x</button></>)}

(2)使用数组map方法渲染出九个Square组件

不同于vue的v-for,react使用数组方法实现列表的渲染

function Board() {// 存储每个格子的值 初始化为空const squares = new Array(9).fill('')const listSquare = squares.map((value, index) => (<Square key={index} />))return (<>{listSquare}</>)}

(3)通过props传递数据

将square组件的值存储在Board里面,通过props传值

function Square({ content }) {return (<><button className='square'>{content}</button></>)}
function Board() {...const listSquare = squares.map((value, index) => (<Square key={index} content={value} />))...}

这样的props传值感觉更清晰,子组件可以接收到props对象,展开的content变量直接就用

再提一嘴react的这个单括号:既可以像vue的插值语法{{}},也像v-bind数据绑定一样传递数据,蛮有意思蛮有意思

2.实现交互效果

(1)点击square显示×号

在sqare组件中实现:

使用useState钩子来实现对数据的记忆和更改,类似于vue的响应式数据

const [content, setContent] = useState('')中:content相当于数据的getter,setContent相当于数据的setter 

function Square() {const [content, setContent] = useState('')function handleClick() {setContent('X')}return (<><button className='square' onClick={handleClick}>{content}</button></>)}

这样虽然实现了点击就改变square的内容,不过改变后的结果Board组件并不能得知 

(2)状态提升

数据存储在square中是无法实现完成O和X的交替点击,以及判定赢家等操作的

因此将点击事件和state存储在父组件Board上,通过props传递给各个square组件即可

function Square({ content, onSquareClick }) {return (<><button className='square' onClick={onSquareClick}>{content}</button></>)}
function Board() {// 存储每个格子的值 初始化为空const [squares, setSquares] = useState(new Array(9).fill(''))// 点击对应索引的square,更新数组function handleClick(index) {const nextSquares = squares.slice()nextSquares[index] = 'X'setSquares(nextSquares)}// 遍历渲染九个square组件const listSquare = squares.map((value, index) => (<Square key={index} content={value} onSquareClick={() => { handleClick(index) }} />))...}

注意:不能直接 onSquareClick={ handleClick(index) } 将函数传给Square组件,因为这样会直接调用点击事件更新state,造成死循环;

可以通过套一层函数调用handleClick解决,因此最便捷的就是直接使用箭头函数调用

(3)不变性

为什么在handleClick函数中要使用slice()复制一个新数组,对其进行更改后再setState?

为了维持不变性,如果直接对state进行修改,当父组件的state改变后,所有的子组件都会跟着重新渲染(包括未受影响的子组件)

不行...我只觉得直接改变state的话那setState的意义在哪里...?为什么要遵守不变性我这个例子没办法充分证明,后续遇到了再看看

(4)交替传值

直接用一个state来保存当前应该填充的内容

// 记录本次点击内容是O还是X
const [isX, setIsX] = useState(true)
// 点击对应索引的square,更新数组
function handleClick(index) {// 如果square内容已经被填充为o或者x 就不进行后续操作if (squares[index] !== '') returnconst nextSquares = squares.slice()if (isX) {nextSquares[index] = 'X'} else {nextSquares[index] = 'O'}setSquares(nextSquares)setIsX(!isX)
}

(5)判定赢家 

判断是否胜利的逻辑就直接copy了,就是能够胜利的情况的数组集合

// 判断是否胜利
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;}

使用变量winner存储结果

const winner = calculateWinner(squares)

如果winner有值了就不能触发点击事件

function handleClick(index) {// 如果square内容已经被填充为o或者x或者游戏结束,就不进行后续操作if (squares[index] !== '' || calculateWinner(squares)) return...
}

写上提示,主题功能就完成了!

function Board() {...const winner = calculateWinner(squares)return (<><div className="content">{/* 判断是正在游戏还是有赢家了 */}{winner ? (<p className='player'>赢家:{winner}</p>) : (<p className='player'>本轮玩家:{isX ? 'X' : 'O'}</p>)}<div className='board'>{listSquare}</div></div></>)}

注释都要包大括号,蛮诡异的^-^

3.全部代码

其实还有个历史回退功能的,懒得写了,这个入门教程已经大致涵盖了react的基础特色; 

function App() {function Square({ content, onSquareClick }) {return (<><button className='square' onClick={onSquareClick}>{content}</button></>)}function Board() {// 存储每个格子的值 初始化为空const [squares, setSquares] = useState(new Array(9).fill(''))// 记录本次点击内容是O还是Xconst [isX, setIsX] = useState(true)// 点击对应索引的square,更新数组function handleClick(index) {// 如果square内容已经被填充为o或者x或者游戏结束,就不进行后续操作if (squares[index] !== '' || calculateWinner(squares)) returnconst nextSquares = squares.slice()if (isX) {nextSquares[index] = 'X'} else {nextSquares[index] = 'O'}setSquares(nextSquares)setIsX(!isX)}// 遍历渲染九个square组件const listSquare = squares.map((value, index) => (<Square key={index} content={value} onSquareClick={() => { handleClick(index) }} />))// 判断是否胜利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;}const winner = calculateWinner(squares)return (<><div className="content">{/* 判断是正在游戏还是有赢家了 */}{winner ? (<p className='player'>赢家:{winner}</p>) : (<p className='player'>本轮玩家:{isX ? 'X' : 'O'}</p>)}<div className='board'>{listSquare}</div></div></>)}return (<><Board /></>)
}

(三)总结

已经学过一门框架了,再看react的话只是思维不太一样,在react里也能看到蛮多vue仿鉴的东西,所以最开始的基础就不像以前一样写的又慢又细了

这个入门井字棋游戏概括了很多的基础知识

1.jsx的函数式编程

2.父子组件的props传递

3.列表的渲染

4.useState HOOK

5.条件渲染

6.响应事件

速度速度,再不学学不完了QAQ

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/769602.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯算法 - DP

上一篇&#xff1a;[[蓝桥杯算法-排序、递归、全排列]] 动态规划&#xff08;dp&#xff09; dp即动态规划&#xff0c;常用于&#xff1a;数学&#xff0c;计算机科学&#xff0c;管理学&#xff0c;经济和生物信息学。 dp在生活中也很常见&#xff0c;如&#xff1a;你今天…

今天聊聊Docker

在数字化时代&#xff0c;软件应用的开发和部署变得越来越复杂。环境配置、依赖管理、版本控制等问题给开发者带来了不小的挑战。而Docker作为一种容器化技术&#xff0c;正以其独特的优势成为解决这些问题的利器。本文将介绍Docker的基本概念、优势以及应用场景&#xff0c;帮…

1.4.2 练习

一、颠倒三角形 题目&#xff1a;修改顶点着色器让三角形上下颠倒 更改顶点着色器代码如下&#xff1a; #version 330 corelayout (location 0) in vec3 aPos; //位置变量的属性位置值为0 layout (location 1) in vec3 aColor; //颜色变量的属性位置值为1out vec3 ourColo…

项目配置之道:优化Scrapy参数提升爬虫效率

前言 在当今信息时代&#xff0c;数据是无处不在且无比重要的资源。为了获取有效数据&#xff0c;网络爬虫成为了一项至关重要的技术。Scrapy作为Python中最强大的网络爬虫框架之一&#xff0c;提供了丰富的功能和灵活的操作&#xff0c;让数据采集变得高效而简单。本文将以爬…

线程和进程有什么区别?

1、典型回答 进程&#xff08;Process&#xff09;和线程&#xff08;Thread&#xff09;是操作系统中两个重要的概念&#xff0c;都是用来执行任务的&#xff0c;它们的定义如下&#xff1a; 进程是指计算机中正在运行的程序的实例。每个进程都有自己的地址空间、内存、文件…

生成词云...

import wordcloud import jieba import PIL import numpy as np import matplotlib.pyplot as plt import jieba.analyse image_background PIL.Image.open(/home/back/pythonclass/11.jpg) #遮罩 MASK np.array(image_background) txtopen("/home/back/pythoncla…

如何本地部署Imagewheel并实现无公网IP远程连接打造个人云图床

文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

Mysql数据库——数据备份与恢复

目录 一、数据备份的重要性 二、数据库备份的分类 1.从物理与逻辑的角度分类 2.从数据库的备份策略角度&#xff0c;备份可分为 2.1完全备份 2.2差异备份 2.3增量备份 2.4总结 三、常见的备份方法 四、Mysql数据库完全备份 1.完全备份定义 2.优缺点 3.数据库完全备…

2024南京人工智能展会:定于2024年11月份在南京国际博览中心举行

2024南京国际人工智能展览会&#xff0c;拟定于2024年11月份在南京国际博览中心隆重召开。这一盛大的科技盛宴&#xff0c;无疑将为全球人工智能领域注入新的活力&#xff0c;推动科技创新与社会进步。 此次展览会将以“智能未来&#xff0c;共创辉煌”为主题&#xff0c;汇聚全…

Hbase 王者荣耀数据表 HBase常用Shell命令

大数据课本&#xff1a; HBase常用Shell命令 在使用具体的Shell命令操作HBase数据之前&#xff0c;需要首先启动Hadoop&#xff0c;然后再启动HBase&#xff0c;并且启动HBase Shell&#xff0c;进入Shell命令提示符状态&#xff0c;具体命令如下&#xff1a; $ cd /usr/local…

解决论文中插入图片显示不完整

点击图片-开始&#xff0c;找到段落中右下角 将行距改为单倍行距

CDP7 下载安装 Flink Percel 包

下载链接&#xff1a;https://www.cloudera.com/downloads/cdf/csa-trial.html 点击后选择版本&#xff0c; 然后点击download now&#xff0c;会有一个协议&#xff0c;勾选即可&#xff0c;然后就有三个文件列表&#xff0c; 我这里是已经注册登录的状态&#xff0c;如果没…

链式二叉树经典OJ题目(一)

目录 结构体声明&#xff1a; 1.单值二叉树 题目描述&#xff1a; 思路分析&#xff1a; 源码&#xff1a; 2.二叉树最大深度 题目描述&#xff1a; 思路分析&#xff1a; 源码&#xff1a; 3.检查两棵树是否相同 题目描述&#xff1a; 思路分析&#xff1a; 源码…

YOLOv9改进策略:卷积魔改 | SCConv:空间和通道重建卷积,即插即用,助力检测 | CVPR2023

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a; CVPR2023 SCConv 由两个单元组成&#xff1a;空间重建单元&#xff08;SRU&#xff09;和通道重建单元&#xff08;CRU&#xff09;。 SRU利用分离重建方法来抑制空间冗余&#xff0c;而CRU使用分割-变换-融…

Linux文件系列:磁盘,文件系统,软硬链接

Linux文件系列:磁盘,文件系统,软硬链接 一.磁盘相关知识1.磁盘机械构成2.磁盘物理存储3.磁盘逻辑存储1.LBA地址2.磁盘的分区和分组 二.文件系统和inode1.inode结构体2.文件系统1.Super Block(超级块)2.Group Descriptor Table(块组描述表GDT)3.inode Table4.Data Blocks5.Block…

mysql面试,事务四大特性,mvcc版本控制,3个重要日志,索引结构,索引失效,innodb引擎执行流程,主从复制,锁,page页

大纲 事务4大特性 https://blog.csdn.net/king_zzzzz/article/details/136699546 Mvcc多版本控制 https://blog.csdn.net/king_zzzzz/article/details/136699546 3个重要日志 https://blog.csdn.net/king_zzzzz/article/details/136868343 索引 mysql 索引&#xff08;…

家用智能洗地机哪个牌子好?4款型号让你解锁高效省力生活体验

在今天的社会中&#xff0c;随着生活节奏的加快&#xff0c;人们对于家庭清洁的需求不断增加。传统的清洁方法已经无法满足现代家庭的需求。因此&#xff0c;洗地机作为一种高效、方便的清洁工具&#xff0c;已经成为了许多家庭首选的清洁设备。然而&#xff0c;在市场上&#…

RSTP、MSTP、VRRP

RSTP协议原理与配置 问题一、STP的收敛延时&#xff08;30秒&#xff08;有BP端口情况下RP端口down&#xff09;或者50秒&#xff08;没有BP端口情况下RP端口down&#xff09;&#xff09; RSTP&#xff1a;Rapid Spanning Tree Protocol RSTP和STP从原理流程上一样&#xf…

【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串

送给大家一句话&#xff1a; 充满着欢乐与斗争精神的人们&#xff0c;永远带着欢乐&#xff0c;欢迎雷霆与阳光。 —— 赫胥黎 滑动窗口精通 前言Leetcode 30. 串联所有单词的子串题目描述算法思路 Leetcode 76. 最小覆盖子串题目描述算法思路 Thanks♪(&#xff65;ω&#xf…

QT 信号(Signal)与槽(Slot)机制

一、信号&#xff08;signal&#xff09;与槽&#xff08;slot&#xff09; 在QT中&#xff0c;信号&#xff08;signal&#xff09;与槽&#xff08;slot&#xff09;机制是一种用于对象间通信的重要机制。它允许一个对象发出信号&#xff0c;而其他对象可以通过连接到该信号…