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)

相关推荐
前端一课几秒前
uniapp之WebView容器原理详解
前端
CryptoRzz3 分钟前
DeepSeek印度股票数据源 Java 对接文档
前端·后端
星星202526 分钟前
MBSE与数字孪生:五大行业案例
笔记
网络点点滴34 分钟前
watch监视-ref基本类型数据
前端·javascript·vue.js
西洼工作室44 分钟前
前端接口安全与性能优化实战
前端·vue.js·安全·axios
大布布将军44 分钟前
《前端九阴真经》
前端·javascript·经验分享·程序人生·前端框架·1024程序员节
幸运小圣1 小时前
for...of vs for 循环全面对比【前端JS】
开发语言·前端·javascript
用户9545156811621 小时前
实际开发中 | 与 || 的使用方法及组件封装方案解析
前端
得帆云低代码1 小时前
COC Asia 2025|得帆云 ETL:顺应 Hive 新特性,重塑数据管道的未来
前端
十字路口的火丁2 小时前
前端开发如何灵活使用 css 变量
前端