网站建设与运营的预算方案,淘宝禁止了网站建设类,nos WordPress,东莞响应式网站价格写在前面#xff1a;
磨磨唧唧了好久终于下定决心开始学react#xff0c;刚刚接触感觉有点无从下脚...新的语法新的格式跟vue就像两种物种...倒是很好奇路由和store是怎么实现的了~v~#xff0c;一点一点来吧#xff01;#xff01;#xff01;
(一)创建项目
使用vite…写在前面
磨磨唧唧了好久终于下定决心开始学react刚刚接触感觉有点无从下脚...新的语法新的格式跟vue就像两种物种...倒是很好奇路由和store是怎么实现的了~v~一点一点来吧
(一)创建项目
使用vite创建 npm create vite 选择react项目欧啦现在开始 main.tsx文件 还是熟悉的味道鉴于我还搞不清楚组件和路由就直接在app.tsx里面开干
(二)制作井字棋游戏
1. 搭建九宫格形状
(1)用Square组件实现小格子
function Square() {return (button classNamesquarex/button/)}
(2)使用数组map方法渲染出九个Square组件
不同于vue的v-forreact使用数组方法实现列表的渲染
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 classNamesquare{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相当于数据的gettersetContent相当于数据的setter function Square() {const [content, setContent] useState()function handleClick() {setContent(X)}return (button classNamesquare onClick{handleClick}{content}/button/)}
这样虽然实现了点击就改变square的内容不过改变后的结果Board组件并不能得知 (2)状态提升
数据存储在square中是无法实现完成O和X的交替点击以及判定赢家等操作的
因此将点击事件和state存储在父组件Board上通过props传递给各个square组件即可
function Square({ content, onSquareClick }) {return (button classNamesquare onClick{onSquareClick}{content}/button/)}
function Board() {// 存储每个格子的值 初始化为空const [squares, setSquares] useState(new Array(9).fill())// 点击对应索引的square更新数组function handleClick(index) {const nextSquares squares.slice()nextSquares[index] XsetSquares(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 classNamecontent{/* 判断是正在游戏还是有赢家了 */}{winner ? (p classNameplayer赢家{winner}/p) : (p classNameplayer本轮玩家{isX ? X : O}/p)}div classNameboard{listSquare}/div/div/)}
注释都要包大括号蛮诡异的^-^
3.全部代码
其实还有个历史回退功能的懒得写了这个入门教程已经大致涵盖了react的基础特色
function App() {function Square({ content, onSquareClick }) {return (button classNamesquare 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 classNamecontent{/* 判断是正在游戏还是有赢家了 */}{winner ? (p classNameplayer赢家{winner}/p) : (p classNameplayer本轮玩家{isX ? X : O}/p)}div classNameboard{listSquare}/div/div/)}return (Board //)
}
(三)总结
已经学过一门框架了再看react的话只是思维不太一样在react里也能看到蛮多vue仿鉴的东西所以最开始的基础就不像以前一样写的又慢又细了
这个入门井字棋游戏概括了很多的基础知识
1.jsx的函数式编程
2.父子组件的props传递
3.列表的渲染
4.useState HOOK
5.条件渲染
6.响应事件
速度速度再不学学不完了QAQ