React 01

1 React 组件必须返回单个 JSX 元素

React 组件必须返回单个 JSX 元素,不能像两个按钮那样返回多个相邻的 JSX 元素。要解决此问题,可以使用 Fragment(<></>)包裹多个相邻的 JSX 元素,如下所示:

javascript 复制代码
export default function Square() {
  return (
    <>
      <button className="square">X</button>
      <button className="square">X</button>
    </>
  );
}

2 React JSX

React JSX | 菜鸟教程https://www.runoob.com/react/react-jsx.html

我们来逐步拆解这段 JSX 代码,理解它的作用:

1. 组件定义

javascript 复制代码
export default function Board() {
  return (
    // ... JSX 内容
  );
}
  • 这是一个 React 函数组件,名为 Board
  • export default 表示将这个组件作为默认导出,方便其他文件引入使用。

2. Fragment(片段)

javascript 复制代码
<>
  {/* 其他内容 */}
</>
  • 这是 React 的 Fragment(片段)语法。
  • 它的作用是在不额外添加嵌套 div 等标签的情况下,将多个元素组合在一起返回。因为 React 组件的返回值必须是一个单一的根元素,Fragment 就解决了这个问题,且不会在 DOM 中添加额外的节点。

3. 渲染行(board-row)和方块(Square

javascript 复制代码
<div className="board-row">
  <Square />
  <Square />
  <Square />
</div>
  • 这里的 div 标签,className="board-row" 是给这个 div 添加 CSS 类名,用于设置样式(比如让一行内的元素排列整齐等)。
  • <Square /> 是在渲染 Square 组件。这里重复渲染了多个 Square 组件,构建出类似井字棋(Tic-Tac-Toe)棋盘的结构,3 行,每行 3 个方块,总共 9 个方块。

整体作用

这段代码定义了一个 Board 组件,它通过 JSX 语法,使用 div 标签分组(每行一个 div,类名为 board-row),并在每个分组里渲染 Square 组件,最终呈现出一个 3×3 的棋盘结构,是构建井字棋等类似棋盘类应用界面的一部分。

你提到的 <Square /> 这一行是在 使用 Square 组件 ,它的作用和后面的 <button> 标签类似,都是在页面上渲染一个元素,只是实现方式不同。

具体可以这样理解:

  1. 组件的复用 :你前面已经定义了 Square 函数组件:

    html 复制代码
    function Square(){
      return <button className = "square">1</button>
    }

    这个组件的功能是返回一个带有 square 类名的按钮,按钮内容是 "1"。

    当你在 Board 组件中写 <Square /> 时,就相当于把上面定义的这个按钮「插入」到了当前位置,和直接写 <button className="square">1</button> 的效果是一样的。

  2. 与直接写 button 的区别 :后面的 <button className="square">2</button> 是直接写死的按钮,而 <Square /> 是通过组件复用的方式渲染的按钮。

    这种组件化的好处是:如果以后需要修改所有方块的样式或行为,只需要改 Square 组件的代码,而不用逐个修改每个按钮。

  3. 为什么这样写 :从代码来看,这可能是一个逐步改造的过程 ------ 先用直接写死的按钮搭建结构,再把重复的按钮逻辑提取成 Square 组件。最终目标可能是把所有 <button> 都替换成 <Square /> 组件,让代码更简洁、更易于维护。

简单说,<Square /> 就像是一个「按钮模板」,用它可以快速生成具有相同样式和基础功能的按钮。

3 React 中如何通过 props(属性)传递数据

这部分内容是在讲解 React 中如何通过 props(属性)传递数据,以及 JSX 中如何正确使用 JavaScript 变量。

1. 最初的问题

最开始,Square 组件直接返回固定内容为 1 的按钮:

html 复制代码
function Square() {
  return <button className="square">1</button>;
}

当在 Board 组件中多次使用 <Square /> 时,所有方块都显示 1,没有了原本不同的编号,这不符合需求。

2. 尝试用 props 传递数据

为了让每个 Square 显示不同的内容,需要从父组件 Board 向子组件 Square 传递数据,这就要用到 props。首先修改 Square 组件,接收 value 属性:

html 复制代码
function Square({ value }) {
  return <button className="square">1</button>;
}

这里 { value } 是解构赋值,从 props 对象中取出 value 属性。但此时按钮里还是固定的 1,因为没有使用传递过来的 value

3. 错误的显示结果

如果直接写 return <button className="square">value</button>;,页面上会显示字符串 "value",而不是 value 变量所代表的值。这是因为在 JSX 中,普通的字符串会被当作文本直接渲染,而不是 JavaScript 变量。

4. 正确的 JSX 语法

要在 JSX 中使用 JavaScript 变量(这里是 value),需要用大括号 {} 把变量包起来,这样就会从 JSX「转义」到 JavaScript,渲染变量的值:

html 复制代码
function Square({ value }) {
  return <button className="square">{value}</button>;
}

这样,当父组件 BoardSquare 传递不同的 value 属性时,每个 Square 就能显示对应的内容了。比如 <Square value="2" />,这个 Square 组件的按钮就会显示 2

简单来说,大括号 {} 在 JSX 中是一个重要的标记,它告诉 React:这里要插入的是 JavaScript 表达式(变量、运算等),而不是普通的字符串文本。

4 useState

这段内容主要讲解了在 React 函数组件中使用 useState 钩子来管理组件的状态,让 Square 组件能够 "记住" 是否被点击过,并在点击时更新显示内容。

1. useState 是什么

useState 是 React 提供的一个钩子函数 (Hook),专门用于在函数组件中添加状态管理功能。在类组件中,我们可以通过 this.statethis.setState 来管理状态,而在函数组件中,就需要借助 useState 等钩子。

2. 导入 useState

javascript 复制代码
import { useState } from 'react';

这行代码的作用是从 react 库中导入 useState 函数,只有导入后,才能在组件中使用它来管理状态。

3. 在 Square 组件中使用 useState

javascript 复制代码
function Square() {
  const [value, setValue] = useState(null);
  // ... 其他代码
}
  • useState(null):调用 useState 并传入初始值 nulluseState 会返回一个数组,数组的第一个元素是状态变量 (这里命名为 value),第二个元素是用来更新状态变量的函数 (这里命名为 setValue)。
  • 初始时,value 的值为 null,因为我们希望 Square 组件一开始没有被点击,没有填充内容。

4. 为什么要移除 value props

之前 Square 组件的内容是通过父组件 Board 传递 value 属性来设置的。现在要让 Square 自己 "记住" 点击状态,所以不再需要从父组件接收 value 属性,而是由组件自身的状态 value 来管理显示内容。

5. 后续逻辑(结合点击事件)

接下来通常会编写点击事件处理函数 handleClick,在这个函数中调用 setValue 来更新 value 的值。比如,当 Square 被点击时,将 value 设置为 'X',这样就能实现点击后用 'X' 填充方块的效果,代码大概会是这样:

javascript 复制代码
function handleClick() {
  setValue('X');
}

然后把 handleClick 函数绑定到按钮的 onClick 事件上:

javascript 复制代码
return <button className="square" onClick={handleClick}>{value}</button>;

这样,当用户点击 Square 对应的按钮时,handleClick 函数被触发,value 被更新为 'X',按钮的显示内容也会随之改变。

总结一下,这部分内容核心是引入 useState 钩子,让 Square 组件拥有自己的状态,从而能够响应点击事件并更新自身显示内容,实现 "记住" 点击状态的功能。

5

JavaScript Array slice() 方法 | 菜鸟教程https://www.runoob.com/jsref/jsref-slice-array.html

1. 整体背景

这段代码是在实现一个类似井字棋(Tic-Tac-Toe)的棋盘逻辑。Board 组件管理着棋盘的状态(squares 数组,用来表示每个格子的内容,初始都是 null,代表空),handleClick 函数是用来处理点击事件,更新棋盘状态的。

2. useState 部分

javascript 复制代码
const [squares, setSquares] = useState(Array(9).fill(null));
  • 这里使用 React 的 useState 钩子来定义状态。
  • squares 是状态变量,它是一个长度为 9 的数组(对应井字棋 3x3 的 9 个格子),每个元素初始值为 null,表示格子初始为空。
  • setSquares 是用来更新 squares 状态的函数,调用它会触发组件重新渲染。

3. handleClick 函数

javascript 复制代码
function handleClick() {
  const nextSquares = squares.slice();
  nextSquares[0] = "X";
  setSquares(nextSquares);
}
(1)slice() 方法的作用
  • squares.slice() 是 JavaScript 数组的 slice 方法。
  • 如果 slice 方法没有传入任何参数(slice()),它会创建一个原数组的浅拷贝即复制一份原数组的内容,生成一个新数组)。
  • 为什么要创建拷贝? 因为在 React 中,状态是不可直接修改的(Immutable)。如果直接修改 squares 数组(比如 squares[0] = "X"),React 无法检测到状态的变化,也就不会触发重新渲染。所以需要先复制出一个新数组,修改新数组,再用新数组去更新状态。
(2)修改新数组并更新状态
  • nextSquares[0] = "X":在新创建的数组 nextSquares 中,将索引为 0 的元素(对应棋盘第一个格子)的值设为 "X"
  • setSquares(nextSquares):调用 setSquares 函数,把修改后的 nextSquares 数组设置为新的 squares 状态。这会让 React 知道状态发生了变化,从而触发 Board 组件及其子组件(比如 Square 组件)重新渲染,页面上就能看到第一个格子显示为 X 了。

4. 重新渲染的逻辑

当调用 setSquares(nextSquares) 后:

  • React 会检测到 squares 状态发生了改变。
  • 于是 Board 组件会重新执行渲染逻辑,它的子组件(那些展示 squares 中对应格子内容的 Square 组件)也会跟着重新渲染,这样页面上的棋盘就会更新为新的状态,我们就能看到第一个格子被填充为 X 了。

简单总结一下,slice() 在这里的核心作用就是复制原数组,生成一个可修改的新数组,从而满足 React 状态不可直接修改的要求,让状态更新能被 React 检测到,进而触发组件重新渲染。

5 传递函数本身和立即调用函数

简单来说,就是:

  • 当你写 onSquareClick={handleClick} 时,是传递函数本身,等需要的时候(比如用户点击)再去调用。
  • 当你写 onSquareClick={handleClick()} 时,是立即调用函数,而不是等点击时才调用,这就会导致不符合预期的执行(比如无限循环、逻辑提前执行)。

文中用箭头函数 () => handleClick(0),就是为了传递一个 "待执行" 的逻辑 :只有当用户点击时,才会执行 handleClick(0)

相关推荐
@大迁世界3 小时前
React 19.2.0 有哪些新变化
前端·javascript·react.js·前端框架·ecmascript
稻草猫.3 小时前
文件 IO
java·笔记·后端·java-ee·idea
QT 小鲜肉4 小时前
【个人成长笔记】Qt Creator快捷键终极指南:从入门到精通
开发语言·c++·笔记·qt·学习·学习方法
华仔啊4 小时前
用 Vue3 + Canvas 做了个超实用的水印工具,同事都在抢着用
前端·vue.js·canvas
lkbhua莱克瓦244 小时前
Java基础——面向对象进阶复习知识点8
java·笔记·github·学习方法
Bacon5 小时前
前端:从0-1实现一个脚手架
前端
Bacon5 小时前
前端项目部署实战 nginx+docker持续集成
前端
beckyye5 小时前
阿里云智能语音简单使用:语音识别
前端·语音识别·录音
东东2335 小时前
前端规范工具之husky与lint-staged
前端·javascript·eslint