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

React:描述UI 官网笔记

文章目录

  • 一、你的第一个组件
    • 1. 什么是组件?(核心定义)
    • 2. 如何定义一个组件?(三个步骤)
    • 3. 组件的组织逻辑(父与子)
    • 4. 核心思想:万物皆组件
  • 二、 组件的导入与导出
      • 1. 为什么要拆分组件?
      • 2. 导出与导入的两种方式
  • 三、使用 JSX 书写标签语言
    • 1. 为什么要使用 JSX?
    • 2. JSX 的核心语法规则
      • ① 只能有一个根元素
      • ② 标签必须闭合
      • ③ JS 表达式要写在花括号 {} 中
      • ④ 属性名使用小驼峰命名 (camelCase)
      • ⑤ 内联样式必须是对象
  • 四、 将 Props 传递给组件
    • 1. 什么是 Props?
    • 2. 如何使用 Props(两步走)
    • 3. 高级传递技巧
    • 4. 特殊属性:children
    • 5. Props 的不可变性 (Immutability)
  • 五、条件渲染
    • 1. 三种常用的逻辑控制方式
    • 2. 详细语法说明
      • A. 条件返回 `null`
      • B. 三元运算符 `? :` (最常用)
      • C. 逻辑与 && (短路运算符)
      • D. 使用变量赋值
  • 六、 列表渲染 (Rendering Lists)
    • 1. 核心方法:`map()` 与 `filter()`
    • 2. 为什么需要 `key`?
    • 3. `key` 的使用规则
    • 4. 常见陷阱与注意事项
  • 七、保持组件纯粹 (Keeping Components Pure)
    • 1. 什么是纯组件 (Pure Components)?
    • 2. 严禁突变 (Mutation):常见的错误
      • ❌ 错误示例:修改外部变量
      • ✅ 正确示例:通过 Props 传递
    • 4. 严格模式 (Strict Mode) 的作用
    • 5. 副作用 (Side Effects) 的安放地
    • 6. 为什么必须保持组件的纯粹性?
      • 1. 提高性能:跳过不必要的渲染
      • 2. 随时中断与恢复:支持并发模式
      • 3. 跨环境运行:从浏览器到服务器
      • 4. 预测性与易于测试
      • 5. 避免渲染顺序导致的 Bug
      • 💡 核心“超能力”总结
    • 💡 核心心法总结
  • 八、将 UI 视为树 (UI as a Tree)
    • 1. 渲染树 (Render Tree)
    • 2. 模块依赖树 (Dependency Tree)
    • 3. 关键区别
    • 4. 快速记忆

一、你的第一个组件

1. 什么是组件?(核心定义)

  • 本质:组件是 React 应用的最小构建单元。它将标签 (HTML)样式 (CSS)交互逻辑 (JS)封装在一起,形成一个独立的、可复用的 UI 模块。
  • 表现形式:在代码层面,组件本质上就是一个返回JSX标签的普通的JavaScript 函数
  • 角色比喻:类似于乐高积木,你可以通过组合、嵌套这些积木来拼出复杂的页面。

2. 如何定义一个组件?(三个步骤)

编写组件时必须遵守的“工业标准”流程:

  1. 导出组件:使用export default关键字,确保该组件可以被其他文件import(引入)。
  2. 定义函数:使用function关键字声明函数。
    • ⚠️ 必记陷阱:组件名称必须以大写字母开头(如Profile而不是profile)。React 依靠首字母大小写来区分它是自定义组件还是原生 HTML 标签。
  3. 编写标签 (JSX)
    • 使用return关键字返回 UI 结构。
    • ⚠️ 格式陷阱:如果标签没有紧跟在return关键字后面(即换行写了),必须用小括号()包裹,否则return下方的代码将被 JS 引擎自动忽略。

3. 组件的组织逻辑(父与子)

  • 嵌套使用:你可以像使用 HTML 标签一样使用组件,例如<Profile />
  • 父子关系:渲染其他组件的组件称为父组件(如Gallery),被渲染的组件称为子组件(如Profile)。
  • ⚠️ 性能陷阱(重点)
    • 永远不要在组件内部定义另一个组件!
    • 原因:每次父组件渲染时,内部定义的子组件都会被重新创建。这不仅极其缓慢,还会导致子组件的状态丢失,产生难以调试的 Bug。
    • 正确做法:所有的组件都应该在文件的最顶层 (Top-level)独立定义。

4. 核心思想:万物皆组件

  • 从局部到整体:在 React 的世界里,小到按钮 (Button)、头像 (Avatar),大到侧边栏 (Sidebar)、列表 (List),甚至整个页面 (Page),都是由组件构成的。
  • 根组件:每个 React 应用都有一个起始点,通常被称为“根组件”(Root Component),在标准脚手架中通常命名为App.jsindex.js
  • 声明式 UI:你只需要通过组件定义 UI “看起来是什么样”,React 的渲染引擎会自动帮你把这些 JavaScript 函数转化为浏览器能够识别并显示的真实HTML DOM

二、 组件的导入与导出

1. 为什么要拆分组件?

  • 可重用性:将组件独立成文件,可以在不同的地方重复使用。
  • 可维护性:减少单个文件的体积,让代码结构更清晰,查找更方便。
  • 模块化:每个文件只负责一个功能,符合“单一职责原则”。

2. 导出与导入的两种方式

这是 JavaScript ES 模块的标准语法,React 深度依赖这两种方式:

特性默认导出 (Default Export)具名导出 (Named Export)
数量限制一个文件有且仅有一个一个文件可以有任意多个
导出语法export default function App() {}export function Profile() {}
导入语法import App from './App.js';import { Profile } from './App.js';
命名灵活性导入时可以自定义名称(如import MyBtn)导入名必须与导出名严格一致
  • 通常,文件中仅包含一个组件时,人们会选择默认导出,而当文件中包含多个组件或某个值需要导出时,则会选择具名导出
  • 同一文件中,有且仅有一个默认导出,但可以有多个具名导出!
  • 文件后缀:在 React 环境下,import Gallery from ‘./Gallery’ 和 ./Gallery.js 通常是通用的,但使用 .js 后缀更符合原生 ES 模块规范。

三、使用 JSX 书写标签语言

1. 为什么要使用 JSX?

在没有 JSX 之前,创建 UI 需要调用繁琐的 React.createElement 函数:

// 不使用 JSXconstelement=React.createElement('h1',{className:'title'},'Hello');// 使用 JSX (直观、易读)constelement=<h1 className="title">Hello</h1>;

2. JSX 的核心语法规则

① 只能有一个根元素

JSX 表达式必须被包裹在一个闭合标签内。如果你不想增加额外的 DOM 层级,可以使用Fragment (<>…</>)

// ❌ 错误:不能并列两个根标签return(<div>A</div><div>B</div>);// ✅ 正确return(<><div>A</div><div>B</div></>);

② 标签必须闭合

在 HTML 中某些标签可以不写结束符号(如<img>),但在 JSX 中,所有标签必须闭合,或者使用自闭合。

<img src="logo.png"/>// ✅ 必须有斜杠闭合<br/>

③ JS 表达式要写在花括号 {} 中

如果你想在 UI 中引用变量、执行运算或调用函数,必须将其包裹在 {} 里。

constname="Gemini";<h1>Hello,{name}</h1>;// 输出: Hello, Gemini<p>1+1={1+1}</p>;// 输出: 1 + 1 = 2

④ 属性名使用小驼峰命名 (camelCase)

JSX 本质上更接近 JavaScript 而非 HTML,因此属性名要遵循 JS 的变量命名规则。

  • class 变为 className(因为 class 是 JS 的保留关键字)。

  • onclick 变为 onClick。

  • tabindex 变为 tabIndex。

⑤ 内联样式必须是对象

在 HTML 中样式是字符串,但在 JSX 中必须是一个对象,且 CSS 属性名也要用小驼峰。

// 注意:外层花括号表示进入 JS 环境,内层表示对象<div style={{color:'red',fontSize:'20px'}}>红色的文字</div>

四、 将 Props 传递给组件

1. 什么是 Props?

  • 定义:Props 是你传递给 JSX 标签的信息,类似于 HTML 的属性(如 src, alt)。

  • 用途:父组件通过 Props 将信息(对象、数组、函数等)传递给子组件。

  • 特性:只读(不可变)。Props 就像一张时间快照,反映了组件在特定瞬间的数据状态。


2. 如何使用 Props(两步走)

向子组件传递:在父组件中像写 HTML 属性一样写 Props。

<Avatar person={{name:'Lin'}}size={100}/>

在子组件中读取:通过解构赋值语法直接获取变量。

functionAvatar({person,size}){// 直接使用 person 和 size}
  • ⚠️ 陷阱:解构时不要忘记花括号 { },否则参数会变成整个 props 对象。

3. 高级传递技巧

  • 默认值:如果父组件没传某个值,可以设置备选默认值。
functionAvatar({size=100}){...}// 仅在 size 缺失或为 undefined 时生效
  • 展开语法 (…):当需要将所有属性原封不动转发给下层时使用。
  • ⚠️ 建议:不要过度使用,清晰的逐个传递通常更有利于代码维护。
<Avatar{...props}/>

4. 特殊属性:children

  • 定义:当你嵌套 JSX 内容时(如 ),嵌套的内容会被父组件在children属性中接收。

  • 比喻:父组件像是一个带有“洞”的容器,children 就是填入这个洞的内容。这种模式常用于布局组件(如面板、网格)。

importAvatarfrom"./components/Avatar";functionCard(props:{hh:string;children:React.ReactNode}){console.log("====================================");console.log("Card props",props);console.log("====================================");return<div className="card">{props.children}</div>;}functionApp(){return(<><Card hh="pk"><Avatar size={100}person={{name:"Katsuko Saruhashi",imageId:"YfeOqp2",}}/></Card></>);}exportdefaultApp;

5. Props 的不可变性 (Immutability)

  • 核心规则:永远不要尝试修改 Props

  • 如何更新:如果需要响应用户输入或改变数据,组件必须“请求”其父组件传递新的 Props 对象

  • 内存管理:旧的 Props 会被丢弃,由 JavaScript 引擎自动回收内存。

场景语法 / 操作示例说明
传递数据<Component name="value" />在父组件中像 HTML 属性一样传递数据。
读取数据function Component({ name }) { ... }在子组件参数中使用解构赋值直接读取属性。
缺失值处理function Component({ name = "默认值" })为可选属性设置默认值,仅在未传值或值为undefined时生效。
包装嵌套 UIfunction Wrapper({ children }) { ... }使用内置的children属性来渲染嵌套在组件内部的 JSX 内容。
属性转发<Component {...props} />使用JSX 展开语法将父组件收到的所有 props 快速转发给子组件。

五、条件渲染

1. 三种常用的逻辑控制方式

在 React 中,我们直接使用 JavaScript 的原生语法来处理 UI 的逻辑分支:

语法适用场景语义口诀
if / else复杂的逻辑判断,或者需要返回完全不同的 JSX 树。“如果…就返回 A,否则返回 B。”
三元运算符? :在 JSX 内部进行“二选一”的局部微调。“是真吗?是就显示 A,不是就显示 B。”
逻辑与&&只有当条件为真时才显示,否则什么都不显示。“如果是真的,就显示它;不是就算了。”

2. 详细语法说明

A. 条件返回null

如果你不希望组件渲染任何内容,可以直接返回null

  • 注意:React 会跳过该组件的渲染,不会在网页 DOM 中产生任何节点。
if(isPacked){returnnull;}return<li className="item">{name}</li>;

B. 三元运算符? :(最常用)

适合在 HTML 结构内部做局部的内容切换。

// 如果已打包显示删除线和对勾,否则只显示名称return(<li>{isPacked?(<del>{name+' ✅'}</del>):(name)}</li>);

C. 逻辑与 && (短路运算符)

适合“有则显示,无则隐藏”的简单开关场景。

// 只有当 isPacked 为 true 时,才渲染对勾return(<li>{name}{isPacked&&'✅'}</li>);

⚠️ 避坑指南:不要把数字放在 && 左侧!

  • {count && <p>消息</p>}:如果 count 是 0,React 会在页面上渲染出数字 0。

  • {count > 0 && <p>消息</p>}:确保左侧是一个明确的布尔值。

D. 使用变量赋值

当判断逻辑非常复杂,导致 JSX 嵌套严重时,这是最清晰、最易维护的方法。

letcontent=name;if(isPacked){content=<del>{name+" ✅"}</del>;}return(<li className="item">{content}</li>);
想要实现…建议使用方案代码示例
页面/组件级的大替换if / else提前返回if (!isLogged) return <LoginPage />;
局部内容的“二选一”三元运算符{ ? : }<span>{isVIP ? '尊享会员' : '普通用户'}</span>
局部内容的“显示或隐藏”逻辑与{ && }{showDetails && <DetailedInfo />}
逻辑太乱、嵌套太深变量赋值(let content)let ui = isPacked ? <del>{name}</del> : name;

六、 列表渲染 (Rendering Lists)

1. 核心方法:map()filter()

React 深度利用 JavaScript 原生方法来处理数据集合,实现声明式渲染:

  • filter()(筛选):用于从原始数组中挑出符合条件的子集。
    • 例如:从人员名单中只挑选出职业为“化学家”的对象。
  • map()(转换):将数据数组中的每一项“映射”为 JSX 元素,生成组件数组。

2. 为什么需要key

key是列表渲染中最重要的属性。它不是传给组件的普通 Prop,而是 React 内部专用的**“身份证”**。

  • 唯一标识key帮助 React 建立数据与组件之间的一一对应关系。
  • 性能优化:当列表发生排序、插入或删除时,React 通过key快速识别哪些元素是移动的、哪些是新出的,从而避免暴力重新渲染整个列表,极大提升效率。
  • 状态保持:防止出现 Bug。如果没有稳定的key,React 可能会错误地关联组件状态(例如:删除第一行文字后,第二行的输入框内容却消失了)。

3.key的使用规则

规则详细说明
兄弟间唯一在同一个map()产生的数组中,每个key必须是唯一的,不要求全局唯一。
稳定性key在组件生命周期内必须保持不变。绝对不要使用Math.random()或时间戳。
来源优先使用数据库主键(ID)、UUID 或数据中具备唯一特性的字段。
位置key必须直接写在map()循环返回的最外层JSX 标签上。

4. 常见陷阱与注意事项

  • 慎用索引 (Index):不要默认使用数组下标作为key。如果列表涉及重新排序、插入或删除,使用索引会导致组件状态错位。
  • 禁止动态生成:在render过程中实时生成的key会导致组件在每次更新时都“彻底销毁并重建”,造成严重的性能问题且会丢失 DOM 状态。
  • Fragment 嵌套
    • 如果你希望map返回多个并列节点(例如一对dtdd),不能使用简写<> </>
    • 必须使用显式的<Fragment key={...}>,因为简写形式不支持携带任何属性。
import{Fragment}from'react';// ...constlistItems=people.map(person=><Fragment key={person.id}><h1>{person.name}</h1><p>{person.bio}</p></Fragment>);

七、保持组件纯粹 (Keeping Components Pure)

1. 什么是纯组件 (Pure Components)?

React 的设计哲学假设你编写的每个组件都是一个纯函数。一个纯组件必须满足以下两个特征:

  • 只负责自己的任务:它不应该更改在调用前就已存在的任何对象或变量。
    • 类比:就像数学公式y = 2 x y = 2xy=2x,计算y yy的过程不应该偷偷改掉外部x xx的值。
  • 输入相同,输出相同:只要propsstatecontext一致,返回的 JSX 必须永远一致。

2. 严禁突变 (Mutation):常见的错误

组件“不纯”最常见的原因是在渲染过程中修改了外部变量。

❌ 错误示例:修改外部变量

letguest=0;functionCup(){// 🔴 错误:在渲染期间更改了函数外部声明的变量guest=guest+1;return<h2>Guest #{guest}</h2>;}

✅ 正确示例:通过 Props 传递

functionCup({guest}){// 🟢 正确:组件输出完全取决于传入的参数return<h2>Guest #{guest}</h2>;}

4. 严格模式 (Strict Mode) 的作用

React 提供了<StrictMode>工具(通常包裹在根组件外)来帮助开发者在开发阶段发现“不纯”的组件。

  • 双调用机制:在开发环境下,React 会故意调用组件函数两次
  • 发现漏洞:如果组件是不纯的(例如修改了外部变量),两次调用会导致结果产生累加或偏差(例如本应显示Guest #1, #2, #3,由于不纯却显示了Guest #2, #4, #6),从而让逻辑漏洞显形。

5. 副作用 (Side Effects) 的安放地

虽然渲染必须保持纯粹,但程序总需要改变数据(如发送请求、启动动画),这些操作被称为“副作用”。为了不干扰纯粹的渲染过程,副作用应该放在:

  1. 首选位置:事件处理程序 (Event Handlers)
    • 例如点击按钮、提交表单时执行的函数。
    • 特点:它们不在渲染期间运行,因此不需要是纯函数。
  2. 最后手段:useEffect
    • 如果某些逻辑必须在组件渲染完成后自动触发。
    • 建议:这是最后的手段,应优先尝试在渲染过程或事件处理程序中表达逻辑。

6. 为什么必须保持组件的纯粹性?

保持组件的纯粹性(Purity)并非只是为了追求代码的“优雅”,它是 React 实现高性能、跨平台以及复杂交互的底层基石

1. 提高性能:跳过不必要的渲染

React 利用“记忆化”(Memoization)技术来优化速度。

  • 原理:如果组件是纯粹的,只要输入(Props)没变,输出(JSX)就一定不会变。
  • 好处:React 可以直接复用上一次渲染的结果,从而省去重新执行函数和计算 Diff 的时间。

2. 随时中断与恢复:支持并发模式

在现代 React(并发模式)中,渲染过程是可以被高优先级任务(如用户输入)打断的。

  • 场景:React 在渲染大型列表时,用户突然点击了取消。
  • 必要性:如果组件是不纯的(例如修改了外部变量),渲染到一半停下会导致外部数据处于“脏状态”。纯组件不改变外部环境,React 可以随时安全地丢弃渲染了一半的结果并重新开始。

3. 跨环境运行:从浏览器到服务器

纯组件不依赖于特定的局部环境(如浏览器的windowdocument对象)。

  • 服务端渲染 (SSR):纯组件保证了服务器生成的 HTML 与客户端渲染的结果完全一致,避免出现“水合不匹配”(Hydration Mismatch)的错误。
  • 可移植性:同一套逻辑可以无缝运行在 React Native(移动端)、Node.js(服务器)等多种环境。

4. 预测性与易于测试

  • 可预测性:组件行为仅取决于输入。调试时你只需要关注Props,而不需要担心当前的系统时间、随机数或全局变量的干扰。
  • 测试友好:你不需要模拟复杂的全局环境,只需传入特定的 Props,即可断言输出的 JSX 是否正确。

5. 避免渲染顺序导致的 Bug

React并不保证组件的渲染顺序(例如它可能先渲染底部的组件,再渲染顶部的组件)。

  • 风险:如果组件 A 在渲染时修改了全局变量,而组件 B 依赖该变量,那么渲染顺序的变化会导致 UI 彻底乱套。
  • 解决:纯组件“独立思考”,互不干扰,无论 React 以什么顺序执行,结果都保持稳定。

💡 核心“超能力”总结

能力说明
可缓存性输入不变,直接复用结果,极大提升渲染速度。
可中断性渲染过程可以安全地暂停或重启,响应更敏捷。
可移植性同样的代码在 Server 和 Client 端运行结果完美一致。
可维护性逻辑清晰,Bug 易于定位,不产生“幽灵”副作用。

一句话总结
保持纯粹是为了让 React 能够完全掌控UI 的更新流程,从而为你提供更好的性能保障和更少的意外 Bug。

💡 核心心法总结

  • UI 即公式U I = f ( d a t a ) UI = f(data)UI=f(data)只要数据 (d a t a datadata) 不变,输出的U I UIUI就不该变。
  • 只读原则:将PropsStateContext视为不可变的快照,永远不要尝试直接在渲染过程中修改它们。
  • 渲染独立性:每个组件都应该“独立思考”,不依赖其他组件的渲染顺序,也不依赖外部环境的随机变动。

八、将 UI 视为树 (UI as a Tree)

1. 渲染树 (Render Tree)

  • 定义:表示组件在特定渲染过程中的嵌套模型。
  • 特性
    • 每个节点代表一个组件。
    • 树的顶端是“根组件”(Root Component)。
    • 动态性:会随 Props 或 State 的改变(条件渲染)而变化。
  • 用途
    • 识别顶级组件:优化它们以减少不必要的子树重绘。
    • 识别叶子组件:优化它们的频繁重渲染性能。

2. 模块依赖树 (Dependency Tree)

  • 定义:表示 JavaScript 模块(文件)之间的导入(import)关系。
  • 特性
    • 节点不仅包括组件文件,还包括逻辑、数据(如.js,.json,.css)。
    • 打包工具(Bundler)依据此树构建生产环境代码。
  • 用途
    • 调试大型捆绑包(Bundle size)问题。
    • 优化代码分割和延迟加载。

3. 关键区别

维度渲染树 (Render Tree)依赖树 (Dependency Tree)
节点内容组件实例文件/模块
关系依据JSX 的嵌套 (Parent-Child)文件头部的import语句
包含范围仅限 React 组件所有导入的资源(函数、样式、图片)

4. 快速记忆

渲染树是“谁在谁里面运行”(UI 逻辑)。
依赖树是“谁引了谁的文件”(工程结构)。

http://www.jsqmd.com/news/702131/

相关文章:

  • R语言决策树回归:非线性数据分析实战指南
  • 15分钟精通BetterJoy:Switch手柄PC适配终极指南,解锁跨平台游戏控制新体验
  • 10个免费Illustrator脚本终极指南:彻底改变你的设计工作流
  • Upsonic AI智能体框架:为金融科技打造安全、可扩展的AI应用
  • nli-MiniLM2-L6-H768实战教程:构建NLI驱动的智能FAQ推荐与追问引导系统
  • Armv8-M安全扩展架构与TrustZone技术实战解析
  • LILYGO T-Connect Pro工业物联网控制器全解析
  • 字节跳动UI-TARS-desktop:混合渲染架构下的高性能桌面应用开发新范式
  • ResourceOverride终极指南:掌控网页资源的强大调试神器
  • 终极指南:如何使用XUnity.AutoTranslator为Unity游戏添加智能翻译
  • Crystal语言高性能HTTP路由库earl:轻量级设计与Radix Tree算法解析
  • Liveblocks实战:从零构建实时协作应用的核心架构与最佳实践
  • 基于多智能体协作的AI学术助手:自动文献检索、分析与综述生成
  • 【AI模型】微调-工具框架
  • 2026 网络安全六大趋势:决定企业安全布局的关键风向
  • 小白也能玩转Hunyuan-MT-7B:3步搭建个人翻译助手
  • Nordic nRF7002 EBII Wi-Fi 6扩展板解析与应用
  • 机器学习在糖尿病预测中的应用与数据预处理
  • Qwen3.5推理模型镜像免配置体验:开箱即用Web界面,零基础上手代码与逻辑问答
  • VSCode调试RTOS任务卡死?揭秘FreeRTOS+Zephyr内核变量实时视图插件(支持任务栈深度/优先级/阻塞原因毫秒级刷新)
  • CosyVoice助力在线教育:Python驱动自动化课件配音与作业批改语音反馈
  • XUnity.AutoTranslator:打破语言障碍,让Unity游戏真正全球化
  • 2026年岳阳性价比高的团建公司推荐,说说知明团建活动新颖、主题丰富靠谱吗 - 工业品网
  • 终极指南:3步解锁微信平板模式,轻松实现安卓多设备登录
  • Phi-3.5-Mini-Instruct生成效果:技术面试模拟对话(含算法题+系统设计+行为问题)
  • 专栏A-AI原生产品设计-05-AI原生产品的竞争壁垒
  • Universal-x86-Tuning-Utility终极指南:释放你电脑隐藏性能的完整方案
  • 2026年知明培训可信度高吗,对比长沙其他同类公司有何优势 - myqiye
  • 合成数据与强化学习训练CLI智能代理实战
  • 终极免费指南:高效解密QQ音乐加密文件qmcdump完全攻略