当前位置: 首页 > news >正文

React 02

1 React 组件的导出以及组件结构的组织

这段内容主要是关于 React 组件的导出以及组件结构的组织,我们逐步来解释:

1. export default 的作用

在 React 中,export default 是用来指定模块的默认导出的。一个模块(通常是一个文件)只能有一个默认导出。当其他文件引入这个模块时,默认导出的内容会被作为该模块的主要内容引入。

2. 组件导出的调整

  • 之前可能 Board 组件是用 export default 导出的,也就是:
    export default function Board() {//...
    }
    
    这时候,index.js(或者其他引入该组件的文件)会把 Board 作为顶层组件来使用。
  • 现在需要把 Game 组件作为顶层组件,所以要:
    • 移除 Board 组件前面的 export default
    • 给 Game 组件添加 export default,也就是:
      export default function Game() {//...
      }
      

    这样,index.js 就会使用 Game 组件作为顶层组件,而不是 Board 组件了。

3. Game 组件的结构

export default function Game() {return (<div className="game"><div className="game-board"><Board /></div><div className="game-info"><ol>{/*TODO*/}</ol></div></div>);
}
  • 最外层的 div 类名为 game,作为整个游戏组件的容器。
  • 里面的 div 类名为 game-board,用来包裹 Board 组件,Board 组件负责渲染棋盘部分。
  • 另一个 div 类名为 game-info,里面的 <ol> 标签目前是一个待办(TODO),后续会用来展示游戏相关的信息,比如下棋的步骤、当前玩家、游戏结果等。

4. 总结

这段内容的核心是调整组件的默认导出,让 Game 成为顶层组件,同时 Game 组件的结构为后续添加游戏信息(如下棋历史、胜负判断等)预留了空间,使整个井字棋应用的结构更加清晰,便于后续功能的扩展。

2 状态管理与数组展开语法

这段代码和说明是关于 React(或类似前端框架中)状态管理与数组展开语法的应用,核心是理解如何通过数组展开语法来维护 “游戏步骤历史” 这类序列型状态。

1. 代码结构与核心逻辑

代码定义了一个 Game 组件(React 组件常见形式),内部有 handlePlay 函数,用于 ** 更新 “游戏历史” 和 “当前玩家(X/O 轮次)”** 这两个状态:

  • setHistory([...history, nextSquares]):更新 “游戏步骤历史” 的状态。
  • setXIsNext(!xIsNext):切换当前玩家(比如从 X 轮到 O 轮,或反之)。

2. 数组展开语法(...history)的作用

... 是数组展开语法(也叫 “扩展运算符”),作用是:把原数组 history 里的所有元素 “拆出来”,逐个放到新数组里

结合代码,[...history, nextSquares] 的效果是:

  • 先把 history 中已有的所有数组元素(每个元素代表某一步的游戏局面)依次放入新数组;
  • 再把 nextSquares(代表 “下一步的游戏局面”)放到新数组的最后。

这样就得到了一个包含所有历史步骤 + 新步骤的 “完整历史数组”。

3. 示例理解(最关键的部分)

官方给的示例非常直观:

  • 假设 history 原本是 [[null,null,null], ["X",null,null]]
    • 第一个元素 [null,null,null]:代表 “游戏初始状态(所有格子都是空的)”;
    • 第二个元素 ["X",null,null]:代表 “第一步,X 下在第一个格子,其余为空”。
  • 假设 nextSquares 是 ["X",null,"O"]:代表 “第二步,O 下在第三个格子,此时局面是 X 在第一格、O 在第三格,中间为空”。

那么 [...history, nextSquares] 生成的新数组就是:[[null,null,null], ["X",null,null], ["X",null,"O"]]—— 把 “初始状态”“第一步”“第二步” 这三个步骤,按顺序整合到了新的历史数组里。

4. 为什么要这么做?

在前端框架(如 React)中,状态是不可直接修改的(要通过 setState 这类方法更新)

如果直接对 history 数组 push 新元素,属于 “修改原数组”,不符合框架的 “不可变状态” 设计思想。

而用 [...history, nextSquares],是创建了一个全新的数组(包含历史 + 新步骤),再通过 setHistory 把 “新数组” 设为新状态 —— 既维护了 “游戏步骤按顺序记录” 的逻辑,又符合 “状态不可变” 的要求。

总结:这段代码通过数组展开语法,优雅地实现了 “游戏步骤历史的追加式更新”,保证每一步都被有序记录,同时遵循前端框架的状态管理规范。

3 React 中 key 属性的特点

key 是 React 中一个特殊的保留属性。创建元素时,React 提取 key 属性并将 key 直接存储在返回的元素上。尽管 key 看起来像是作为 props 传递的,但 React 会自动使用 key 来决定要更新哪些组件。组件无法询问其父组件指定的 key。

key 作为 React 内部用于优化渲染性能的特殊属性,有几个关键特性需要明确:

  1. 唯一性与作用域key 在兄弟节点之间必须唯一(无需全局唯一),React 通过它识别元素的身份,判断是复用还是重新创建组件。

  2. 非 props 特性:尽管写法上类似 props(如 <Item key={id} />),但子组件无法通过 this.props.key 或 props.key 获取 key 的值,它完全由 React 内部管理。

  3. 渲染优化核心:当列表数据变化时,React 会对比新旧节点的 key

    • 若 key 相同,尝试复用原有组件并更新内容;
    • 若 key 不同,则销毁旧组件并创建新组件。
  4. 避免使用索引作为 key:在列表项可能重排、增删的场景中,使用索引作为 key 会导致 React 误判元素身份,反而影响性能或引发状态错乱,推荐使用数据自身的唯一标识(如 ID)。

理解 key 的作用机制,有助于更高效地编写 React 列表渲染逻辑,避免因 key 使用不当导致的性能问题或异常行为。

------------

实战一:井子棋源代码

import { useState } from 'react';function Square({ value, onSquareClick }) {return (<button className="square" onClick={onSquareClick}>{value}</button>);
}function Board({ xIsNext, squares, onPlay }) {function handleClick(i) {if (calculateWinner(squares) || squares[i]) {return;}const nextSquares = squares.slice();if (xIsNext) {nextSquares[i] = 'X';} else {nextSquares[i] = 'O';}onPlay(nextSquares);}const winner = calculateWinner(squares);let status;if (winner) {status = 'Winner: ' + winner;} else {status = 'Next player: ' + (xIsNext ? 'X' : 'O');}return (<><div className="status">{status}</div><div className="board-row"><Square value={squares[0]} onSquareClick={() => handleClick(0)} /><Square value={squares[1]} onSquareClick={() => handleClick(1)} /><Square value={squares[2]} onSquareClick={() => handleClick(2)} /></div><div className="board-row"><Square value={squares[3]} onSquareClick={() => handleClick(3)} /><Square value={squares[4]} onSquareClick={() => handleClick(4)} /><Square value={squares[5]} onSquareClick={() => handleClick(5)} /></div><div className="board-row"><Square value={squares[6]} onSquareClick={() => handleClick(6)} /><Square value={squares[7]} onSquareClick={() => handleClick(7)} /><Square value={squares[8]} onSquareClick={() => handleClick(8)} /></div></>);
}export default function Game() {const [history, setHistory] = useState([Array(9).fill(null)]);const [currentMove, setCurrentMove] = useState(0);const xIsNext = currentMove % 2 === 0;const currentSquares = history[currentMove];function handlePlay(nextSquares) {const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];setHistory(nextHistory);setCurrentMove(nextHistory.length - 1);}function jumpTo(nextMove) {setCurrentMove(nextMove);}const moves = history.map((squares, move) => {let description;if (move > 0) {description = 'Go to move #' + move;} else {description = 'Go to game start';}return (<li key={move}><button onClick={() => jumpTo(move)}>{description}</button></li>);});return (<div className="game"><div className="game-board"><Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /></div><div className="game-info"><ol>{moves}</ol></div></div>);
}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;
}

http://www.dtcms.com/a/499703.html

相关文章:

  • 营销网站定制深圳设计展2022
  • MPLS技术详解3:LDP实验与配置实践
  • 上海网站seo设计百度地图电脑版网页
  • 建设 政务数据共享网站网页搜索功能怎么实现
  • 手写Spring第4弹: Spring框架进化论:15年技术变迁:从XML配置到响应式编程的演进之路
  • [优选算法专题四.前缀和——NO.26二维前缀和]
  • 青岛做网站皆赴青岛博网站建设方案论文1500
  • SQL入门:同环比计算法全解析
  • 基于51单片机的12路病房呼叫系统设计与实现
  • Netty面试重点-2
  • 手机网站报价表贵州省住房和城乡建设部网站
  • 网站建设名深圳市seo上词多少钱
  • Vue+element ui导入组件封装——超级优雅版
  • Orleans StreamInstruments 作用分析
  • 全虚拟化、半虚拟化和SR-IOV直通-三种I/O虚拟化技术的核心差异
  • 《打造国漫唐风沉浸感:角色衣袂物理模拟的场景化技术方案》
  • 【三维分割】LangSplatV2:高维的语言3DGS,快到450+FPS
  • Kubernetes(k8s) —— 简介
  • 雅安工程交易建设网站建高级网站
  • 不止于S3:RustFS的多协议网关之路,如何平滑对接HDFS与WebDAV?
  • GIT 实战命令操作大全,代码变动,推动,修改备注,撤销(篇幅一)
  • 网站建设的 关键词家具公司网页设计
  • 蓝牙HCI指令
  • git命令——基础
  • 网站建设的总结200字wordpress长微博工具
  • Qt Q_ENUM和Q_ENUM_NS的区别?
  • 【机器人学中的状态估计】2.1 习题:证明p维高斯概率密度函数积分为1
  • 网站建设合同范本简易版邯郸有什么互联网大公司吗
  • 凡科建站的怎么取消手机网站怎么登录住建局官网
  • 什么是智能管理平台?