初识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.rhkb.cn/news/285769.html

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

相关文章

FreeRtos学习笔记(12)systemView 分析任务调度情况

FreeRtos学习笔记&#xff08;12&#xff09;systemView 分析任务调度情况 使用stm32f429 freertosV10.5.1 systemView 3.5 keil AC5 systemView 移植 从官网下载 systemView 软件 将下面文件添加到工程中 freertos 修改 systemView 需要 FreeRTOSConfig.h 开启如下宏, …

Affinity Photo:像素大师,影像重塑者 mac/win版

在数字图像处理领域&#xff0c;Affinity Photo已经崭露头角&#xff0c;成为许多专业摄影师和图像设计师的首 选工具。这款软件不仅具备丰富的功能和强大的性能&#xff0c;还提供了直观易用的操作界面&#xff0c;让用户能够轻松实现高质量的图像处理。 Affinity Photo软件获…

如何在iOS系统抓取log

前言&#xff1a;因为作者目前工作领域和苹果智能家居有关&#xff0c;然后发现一些bug其实是apple sdk原生code的问题&#xff0c;所以需要给apple提radar单&#xff0c;就需要抓ios端Log充当证据给apple看&#xff0c;其实ios抓log非常简单&#xff0c;大家感兴趣可以学习下哦…

众邦科技CRMEB商城商业版任意文件写入getshell 0day

代码审计 接口&#xff1a;/adminapi/system/crud 处理的代码如下 public function save(SystemCrudDataService $service, $id 0){$data $this->request->postMore([[pid, 0],//上级菜单id[menuName, ],//菜单名[tableName, ],//表名[modelName, ],//模块名称[table…

NAT---网络地址转换技术

Network Address Translation 1、起源&#xff1a;ip地址不够用 2、作用&#xff1a;让私网地址映射成公网地址&#xff0c;进而访问网络。 3、私网Ip地址的范围&#xff1a; A类&#xff1a;10.0.0.0-10.255.255.255 B类&#xff1a;172.16.0.0-172.31.255.255 C类&…

论文精读 | 2024 [ICLR] TimeMixer: 可分解多尺度融合的时间序列预测

论文标题&#xff1a;TimeMixer: Decomposable Multiscale Mixing for Time Series Forecasting 作者&#xff1a;Shiyu Wang&#xff08;王世宇&#xff09;, Haixu Wu&#xff08;吴海旭&#xff09;, Xiaoming Shi, Tengge Hu, Huakun Luo, Lintao Ma, James Y. Zhang, and…

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——禁忌搜索+模拟退火算法(TS+SA)

基于python语言&#xff0c;采用经典禁忌搜索&#xff08;TS&#xff09;模拟退火&#xff08;SA&#xff09;对 需求拆分车辆路径规划问题&#xff08;SDVRP&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整3. 求解结果3.1 TS3.2 SA 4. 代码片段参考 往期优质…

MySQL索引(图文并茂)

目录 一、索引的概念 二、索引的作用 三、创建索引的原则依据 四、索引的分类和创建 1、索引的分类 2、索引的创建 2.1 普通索引 2.1.1 直接创建索引 2.1.2 修改表方式创建 2.1.3 创建表的时候指定索引 2.2 唯一索引 2.2.1 直接创建唯一索引 2.2.2 修改表方式创建 …

C 多维数组

C 语言支持多维数组。多维数组声明的一般形式如下&#xff1a; type name[size1][size2]...[sizeN];例如&#xff0c;下面的声明创建了一个三维 5 . 10 . 4 整型数组&#xff1a; int threedim[5][10][4];二维数组 多维数组最简单的形式是二维数组。一个二维数组&#xff0c…

每秒批量插入10000条数据到MySQL中,资源消耗(带宽、IOPS)有多少?

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容起因代码资源情况改造 &#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、…

Redis入门到实战-第十二弹

Redis实战热身Bitfields篇 完整命令参考官网 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的&#xff08;采用BSD许可证&#xff09;&#xff0c;用作数据库、缓存、消息代理…

Elasticsearch:使用在本地计算机上运行的 LLM 以及 Ollama 和 Langchain 构建 RAG 应用程序

无需 GPU 的隐私保护 LLM。在本博客中&#xff0c;我将演示使用不同的工具 Ollama 构建的 RAG 应用程序。 与本文相关的所有源代码均已发布在 github上。 请克隆存储库以跟随文章操作。我们可以通过如下的方式来克隆&#xff1a; git clone https://github.com/liu-xiao-guo/o…

Unity 学习笔记 5.控制飞机飞行

目录 1.摄像机跟随的方法 2.鼠标按键响应 3.键盘按键响应 4.导入素材 5.让飞机向前飞 6.摄像机跟随飞机移动 7.鼠标控制飞机倾斜 8.键盘控制飞机飞行 下载源码 UnityPackage 1.摄像机跟随的方法 2.鼠标按键响应 3.键盘按键响应 4.导入素材 下载素材 步骤&#xff1a; 将…

itextPdf生成pdf简单示例

文章环境 jdk1.8&#xff0c;springboot2.6.13 POM依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version></dependency><dependency><groupId>com.ite…

3/21 work

自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面。&#xff08;不要使用课堂上的图片和代码&#xff0c;自己发挥&#xff0c;有利于后面项目的完成&#xff09; 要求&#xff1a; 1. 需要使用Ui界面文件进行界面设计 2. ui界面上的组件相关设置&#xff0c;通…

网络——套接字编程UDP

目录 端口号 源端口号和目的端口号 认识TCP协议和UDP协议 网络字节序 socket编程接口 socket常见接口 sockaddr结构 UDP socket bind recvfrom sendto 编写客户端 绑定INADDR_ANY 实现聊天功能 端口号 在这之前我们已经说过源IP地址和目的IP地址&#xff0c;还有…

【vue核心技术实战精讲】1.6 - 1.8 VUE 指令 (中)

文章目录 前言 本节内容1、v-on使用v-on好处效果 2、事件修饰符2.1、按键码 (<font color red>已废弃&#xff0c;不用研究)示例效果 3、v-for 列表渲染示例效果 前言 上节,我们学习了 Vue指令之v-text 、 v-html、v-if 、v-show、v-bind 点击进入上一节 本节内容 Vue…

敏捷开发——第二次作业JS/服务器的部署

部署 Web 服务器 1. 安装 Apache HTTP 服务器并部署静态网页应用 ⭐⭐ 默认情况下&#xff0c;Apache 在 /var/www/html 目录下寻找要提供服务的文件。可以将静态网页文件放置在这个目录下 2.安装 Nginx 并部署静态页面应用 3. 实践部分 1. 2. 3. 在 /var/www/html 目录下…

matlab 条件数的倒数

目录 一、概述1、算法概述2、主要函数3、参考文献二、条件设置错误的矩阵的敏感度三、求解单位矩阵的条件四、参考链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述 1、算法概述

快速上手 Elasticsearch:Docker Compose 部署详解

最近面试竞争日益激烈&#xff0c;Elasticsearch作为一款广泛应用的中间件&#xff0c;几乎成为面试中必考的知识点。最近&#xff0c;AIGC也备受关注&#xff0c;而好多的AI项目中也采用了Elasticsearch作为向量数据库&#xff0c;因此我们迫切希望学习Elasticsearch。对于学习…