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

news/2024/4/29 5:35:44/文章来源:https://blog.csdn.net/DogEgg_001/article/details/136988898

写在前面:

磨磨唧唧了好久终于下定决心开始学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.luyixian.cn/news_show_1027733.aspx

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

相关文章

Reactor设计模式和Reactor模型

Reactor设计模式 翻译过来就是反应堆&#xff0c;所以Reactor设计模式本质是基于事件驱动。 角色 Handle&#xff08;事件&#xff09;EventHandler&#xff08;事件处理器&#xff09;ConcreteEventHandler&#xff08;具体事件处理器&#xff09;Synchronous Event Demult…

QT实现蒙层效果

一.蒙层的作用 1.为了其他窗口不被误操作&#xff0c;禁止对其他窗口操作 二.应用场景 1.一些触摸屏设备上弹出一个dialog窗口&#xff0c;在操作这个窗口的时候不希望后面的窗口被误操作 2.之前做一个医疗设备就曾有过这种需求&#xff0c;因为医疗设备对安全性要求非常高&…

利用 Scapy 库编写 ARP 缓存中毒攻击脚本

一、ARP 协议基础 参考下篇文章学习 二、ARP 缓存中毒原理 ARP&#xff08;Address Resolution Protocol&#xff09;缓存中毒是一种网络攻击&#xff0c;它利用了ARP协议中的漏洞&#xff0c;通过欺骗或篡改网络中的ARP缓存来实施攻击。ARP协议是用于将IP地址映射到物理MAC…

各大pdf转word软件都用的哪家的ocr引擎?

国内一般的PDF软件一般都调用某国际PDF原厂的OCR接口&#xff0c;但这家公司是主要做PDF&#xff0c;在OCR方面并不专注&#xff0c;一些不是很复杂的场景还能应付得过来&#xff0c;复杂一点的效果就强差人意了&#xff0c;推荐用金鸣表格文字识别系统&#xff0c;它主要有以下…

基于树莓派实现 --- 智能家居

最效果展示 演示视频链接&#xff1a;基于树莓派实现的智能家居_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tr421n7BM/?spm_id_from333.999.0.0 &#xff08;PS&#xff1a;房屋模型的搭建是靠纸板箱和淘宝买的家居模型&#xff0c;户型参考了留学时短租的公寓~&a…

Linux repo基本用法: 搭建自己的repo仓库[服务端]

概述 Repo的使用离不开Git, Git 和 Repo 都是版本控制工具&#xff0c;但它们在使用场景和功能上有明显区别… Git 定义&#xff1a;Git 是一个分布式的版本控制系统&#xff0c;由 Linus Torvalds 为 Linux 内核开发而设计&#xff0c;现已成为世界上最流行的版本控制软件之…

【详细讲解PostCSS如何安装和使用】

&#x1f308;个人主页:程序员不想敲代码啊&#x1f308; &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f3c6; &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d; 希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提…

Leetcode146. LRU 缓存

Every day a Leetcode 题目来源&#xff1a;146. LRU 缓存 解法1&#xff1a;哈希表 链表 代码&#xff1a; /** lc appleetcode.cn id146 langcpp** [146] LRU 缓存*/// lc codestart class LRUCache { private:unordered_map<int, list<pair<int, int>>:…

图解Kafka架构学习笔记(二)

kafka的存储机制 https://segmentfault.com/a/1190000021824942 https://www.lin2j.tech/md/middleware/kafka/Kafka%E7%B3%BB%E5%88%97%E4%B8%83%E5%AD%98%E5%82%A8%E6%9C%BA%E5%88%B6.html https://tech.meituan.com/2015/01/13/kafka-fs-design-theory.html https://feiz…

华为防火墙配置指引超详细(包含安全配置部分)以USG6320为例

华为防火墙USG6320 华为防火墙USG6320是一款高性能、高可靠的下一代防火墙,适用于中小型企业、分支机构等场景。该防火墙支持多种安全功能,可以有效抵御网络攻击,保护网络安全。 目录 华为防火墙USG6320 1. 初始配置 2. 安全策略配置 3. 防火墙功能配置 4. 高可用性配…

四种常用限流算法、固定窗口限流算法、滑动窗口限流算法、漏桶限流算法和令牌桶限流算法

什么是限流&#xff1f; 限流可以被视为服务降级的一种形式&#xff0c;其核心目标是通过控制输入和输出流量来保护系统。通常&#xff0c;一个系统的处理能力是可以预估的&#xff0c;为了确保系统的稳定运行&#xff0c;当流量达到预定的阈值时&#xff0c;必须采取措施限制进…

在宝塔面板中,为自己的云服务器安装SSL证书,为所搭建的网站启用https(主要部分攻略)

前提条件 My HTTP website is running Nginx on Debian 10&#xff08;或者11&#xff09; 时间&#xff1a;2024-3-28 16:25:52 你的网站部署在Debain 10&#xff08;或者11&#xff09;的 Nginx上 安装单域名证书&#xff08;默认&#xff09;&#xff08;非泛域名&#xf…

数据结构与算法(二)优先队列

数据结构与算法&#xff08;二&#xff09; 优先队列 一、优先队列的基本概念 我们的电脑总是运行着多个程序&#xff0c;电脑会给每个程序分配一个优先级&#xff0c;并首先执行下一个优先级更高的程序。在此情况下&#xff0c;可将其抽象为一个数据结构&#xff0c;该数据结构…

鸿蒙HarmonyOS开发-FA模型访问Stage模型DataShareExtensionAbility

无论FA模型还是Stage模型&#xff0c;数据读写功能都包含客户端和服务端两部分。 FA模型中&#xff0c;客户端是由DataAbilityHelper提供对外接口&#xff0c;服务端是由DataAbility提供数据库的读写服务。 Stage模型中&#xff0c;客户端是由DataShareHelper提供对外接口&…

【JavaEE】_Spring MVC项目获取URL中的参数

目录 1. 单参数 2. 多参数 1. 单参数 .java文件如下&#xff1a; package com.example.demo.controller;import com.example.demo.Person; import org.springframework.web.bind.annotation.*;import java.util.Arrays; import java.util.List;RequestMapping("/Para&…

SpringBoot Redis 之Lettuce 驱动

一、前言 一直以为SpringBoot中 spring-boot-starter-data-redis使用的是Jredis连接池&#xff0c;直到昨天在部署报价系统生产环境时&#xff0c;因为端口配置错误造成无法连接&#xff0c;发现报错信息如下&#xff1a; 一了解才知道在SpringBoot2.X以后默认是使用Lettuce作…

jmeter中参数加密

加密接口常用的方式有&#xff1a; MD5&#xff0c;SHA&#xff0c;HmacSHA RSA AES&#xff0c;DES&#xff0c;Base64 压测中有些参数需要进行加密&#xff0c;加密方式已接口文档为主。 MD5加密 比如MD5加密的接口文档&#xff1a; 请求URL&#xff1a;http://101.34.221…

【机器学习】数据探索(Data Exploration)---数据质量和数据特征分析

一、引言 在机器学习项目中&#xff0c;数据探索是至关重要的一步。它不仅是模型构建的基础&#xff0c;还是确保模型性能稳定、预测准确的关键。数据探索的过程中&#xff0c;数据质量和数据特征分析占据了核心地位。数据质量直接关系到模型能否从数据中提取有效信息&#xff…

linux中查看内存占用空间

文章目录 linux中查看内存占用空间 linux中查看内存占用空间 使用 df -h 查看磁盘空间 使用 du -sh * 查看每个目录的大小 注意这里是当前目录下的文件大小&#xff0c;查看系统的可以回到根目录 经过查看没有发现任何大的文件夹。 继续下面的步骤 如果您的Linux磁盘已满&a…

VScode中cmake调试

一般的cmake命令行测试方法&#xff1a; cmake -S . -B build cmake --build build ./build/cmake_debug 在vscode中使用图形化界面操作的方法 main.cpp #include <iostream>int main() {int num_a, num_b;num_a 10;num_b 20;std::cout << "num_a &qu…