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

React 08

1 map遍历数组

map 是 JavaScript 中数组的一个常用方法,作用是遍历数组中的每个元素,对它们进行处理后,返回一个新的数组。它不会改变原数组,非常适合在 React 中动态生成列表(比如你之前看到的化学家列表)。

举个简单的例子理解 map

假设你有一个数组 [1, 2, 3],想把每个数字都乘以 2,得到 [2, 4, 6],用 map 可以这样写:

const numbers = [1, 2, 3];
// 用 map 遍历每个元素,返回新数组
const doubled = numbers.map(function(number) {return number * 2; // 对每个元素做处理(乘以 2)
});
console.log(doubled); // 输出 [2, 4, 6]

map 的核心用法:

数组.map(function(当前元素, 索引, 原数组) {// 对当前元素进行处理return 处理后的结果; // 这个结果会组成新数组
});
  • 参数 1(必填):当前正在遍历的元素(比如上面例子中的 123)。
  • 返回值:必须有 return,否则新数组会是 [undefined, undefined, ...]

在 React 中为什么常用 map

因为 React 经常需要根据数组数据动态生成 UI 元素(比如列表项 <li>)。比如你有一个化学家数组 chemists,每个元素是一个对象(包含 nameachievement 等属性),用 map 可以快速把每个对象转换成一个 <li>

const chemists = [{ name: '居里夫人', achievement: '发现镭' },{ name: '门捷列夫', achievement: '发明元素周期表' }
];// 用 map 把每个化学家对象转成 <li>
const listItems = chemists.map(person => {return (<li key={person.name}><h3>{person.name}</h3><p>成就:{person.achievement}</p></li>);
});// 最后把 listItems 渲染到页面
return <ul>{listItems}</ul>;

这样就会生成一个包含两位化学家信息的列表,比手动写两个 <li> 更灵活(如果数组有 100 个元素,map 也能一键处理)。

记住两个关键点:

  1. map 会返回一个新数组,原数组不变。
  2. React 中用 map 生成列表时,每个元素需要加一个唯一的 key 属性(比如上面的 key={person.name}),帮助 React 高效更新 UI。

只有数组能直接调用 map,但其他数据结构可以通过 “转数组” 的方式间接使用 map 的逻辑

map 方法是数组的专属方法,只有数组类型可以直接调用 map。不过,如果你想对其他数据结构(比如对象、字符串等)实现类似 “遍历并转换” 的效果,可以通过一些方式间接实现:

1. 对象的 “类 map” 处理

对象本身没有 map 方法,但可以通过 Object.keys()Object.values() 或 Object.entries() 先把对象转成数组,再用 map

const person = { name: '小明', age: 20, job: '程序员' };// 遍历对象的“键”
const keys = Object.keys(person).map(key => key); 
console.log(keys); // 输出 ['name', 'age', 'job']// 遍历对象的“值”
const values = Object.values(person).map(value => value); 
console.log(values); // 输出 ['小明', 20, '程序员']// 遍历对象的“键值对”
const entries = Object.entries(person).map(([key, value]) => `${key}: ${value}`); 
console.log(entries); // 输出 ['name: 小明', 'age: 20', 'job: 程序员']

2. 字符串的 “类 map” 处理

字符串也没有 map 方法,但可以先转成数组(用 split('') 拆成单个字符),再用 map

const str = 'hello';
const newStrArr = str.split('').map(char => char.toUpperCase()); 
console.log(newStrArr.join('')); // 输出 'HELLO'

3. 其他可迭代对象(如 Set、Map)

ES6 中的 Set(集合)、Map(映射)是可迭代对象,可以通过扩展运算符 ... 转成数组后用 map

const mySet = new Set([1, 2, 3]);
const setArr = [...mySet].map(num => num * 2); 
console.log(setArr); // 输出 [2, 4, 6]const myMap = new Map([['a', 1], ['b', 2]]);
const mapArr = [...myMap.values()].map(num => num + 1); 
console.log(mapArr); // 输出 [2, 3]

总结:只有数组能直接调用 map,但其他数据结构可以通过 “转数组” 的方式间接使用 map 的逻辑,从而实现遍历和转换的效果。

2 箭头函数

箭头函数表达式 - JavaScript | MDNhttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions#%E6%8F%8F%E8%BF%B0这个语法是jsx吗,箭头=>有点没看懂

const chemists = [{ name: '居里夫人', achievement: '发现镭' },{ name: '门捷列夫', achievement: '发明元素周期表' }
];// 用 map 把每个化学家对象转成 <li>
const listItems = chemists.map(person => {return (<li key={person.name}><h3>{person.name}</h3><p>成就:{person.achievement}</p></li>);
});// 最后把 listItems 渲染到页面
return <ul>{listItems}</ul>;

是的,这段代码里的 <li><h3> 等标签写法就是 JSX(JavaScript XML),它是 React 中用于描述 UI 的语法扩展,允许在 JavaScript 中直接写 HTML 风格的标签。

而你提到的 => 是 JavaScript 中的 箭头函数(Arrow Function),是一种更简洁的函数写法,在 React 中非常常用。我们结合你的例子具体解释:

1. 先理解箭头函数 =>

原来的普通函数写法是这样的:

// 普通函数
function(参数) {// 函数体return 结果;
}

箭头函数可以简化成:

// 箭头函数(去掉 function,参数后加 =>)
(参数) => {// 函数体return 结果;
}

如果只有一个参数,甚至可以省略括号:

参数 => {// 函数体return 结果;
}

2. 结合你的例子看

代码中的 chemists.map(person => { ... }) 里,person => { ... } 就是一个箭头函数,作为 map 方法的参数(回调函数)。

它等价于用普通函数写:

chemists.map(function(person) {  // 普通函数写法return (<li key={person.name}><h3>{person.name}</h3><p>成就:{person.achievement}</p></li>);
});

箭头函数在这里的作用和普通函数完全一样:接收 map 遍历到的当前元素(这里是 person,即每个化学家对象),然后返回一个处理后的结果(这里是 JSX 元素 <li>)。

3. 为什么 React 中常用箭头函数?

  • 写法更简洁,尤其在 mapsetTimeout 等需要传匿名函数的场景下,代码更清爽。
  • 箭头函数没有自己的 this,它的 this 继承自外层作用域,在 React 组件中能避免一些 this 指向的问题(后续学组件时会更有体会)。

总结:

  • <li> 这些标签是 JSX,让你能在 JS 中写 UI 结构。
  • => 是 箭头函数,是简化的函数写法,这里作为 map 的回调,处理每个数组元素并返回 JSX。

3 key

在 React 中,key 是一个特殊的属性,主要作用是帮助 React 高效地区分和管理列表中的元素,从而优化渲染性能、避免 bug。具体可以从以下几个维度理解:

1. 核心作用:给 React 一个 “元素身份标识”

当列表中的元素发生变化(新增、删除、重新排序)时,React 需要判断哪些元素是 “旧的”、哪些是 “新的”。key 就像元素的 “身份证”,让 React 能快速识别:

  • 如果两个元素的 key 相同,React 认为它们是同一个元素,只会更新其内容(而不是销毁再重建)。
  • 如果 key 不同,React 会认为是新元素,需要创建;或旧元素被删除,需要销毁。

2. 解决的问题:避免性能浪费和状态异常

如果不写 key(或用了不合适的 key,比如数组索引),React 会默认用索引当 key,这在列表顺序变化时(如插入、删除)会引发问题:

  • 性能问题:假设列表是 [A, B, C],后来变成 [B, A, C]。如果用索引当 key,React 会误判 “第一个元素还是 A”(因为索引 0 没变),但实际 A 已经移动到第二个位置了。这会导致 React 重复创建 / 销毁元素,浪费性能。

  • 状态异常问题:比如列表项包含用户输入(如输入框),如果 key 不稳定,React 会把旧元素的状态错误地绑定到新元素上,导致用户输入 “串位” 或丢失。

3. 正确使用 key 的原则

  • 唯一性:列表中每个元素的 key 必须唯一(不能重复)。
  • 稳定性key 要从数据本身获取(如数据的 id),不能动态生成(如 Math.random())或依赖临时状态(如数组索引)。

示例对比:有 key vs 无 key

// 正确用法:用数据的唯一 id 当 key
{recipes.map(recipe => (<div key={recipe.id}><h2>{recipe.name}</h2></div>
))}// 错误用法1:用数组索引当 key(列表顺序变化时会出问题)
{recipes.map((recipe, index) => (<div key={index}><h2>{recipe.name}</h2></div>
))}// 错误用法2:动态生成 key(每次渲染 key 都变,性能极差)
{recipes.map(recipe => (<div key={Math.random()}><h2>{recipe.name}</h2></div>
))}

总结来说,key 是 React 优化列表渲染的 “关键工具”—— 通过给每个元素一个稳定、唯一的标识,让 React 能精准识别元素的变化,从而高效更新 UI、避免各种隐藏 bug。

4 React 中使用 key 属性时需要避免的陷阱和正确做法

  1. 避免用数组索引作为 key虽然 React 会默认把数组项的索引当作 key,但当数组发生插入、删除、重新排序等操作时(即数组项顺序改变),使用索引作为 key 可能会导致难以察觉的 bug。因为 React 依赖 key 来识别元素的稳定性,索引变化会让 React 误判元素的身份,进而影响渲染效率或导致状态异常。

  2. 禁止动态生成 key(如随机值)像 key={Math.random()} 这类动态生成 key 的方式是不可取的。每次重新渲染时 key 都会变化,这会迫使 React 销毁并重新创建所有相关组件和 DOM 元素,不仅降低性能,还可能导致用户输入(如表单内容)丢失。

  3. key 的正确来源应使用从数据中稳定获取的值作为 key(比如数据本身包含的唯一 ID),确保 key 在元素的生命周期内保持不变。

  4. key 与 props 的区别key 是 React 内部使用的标识,不会作为 props 传递给组件。如果组件需要用到 ID 信息,需单独通过 props 传递(如 <Profile key={id} userId={id} />)。

总结来说,核心是要保证 key 的唯一性稳定性,这样才能让 React 高效、正确地管理组件和 DOM 元素的更新。

5 分析渲染列表的组件

import { recipes } from './data.js';export default function RecipeList() {return (<div><h1>菜谱</h1>{recipes.map(recipe =><div key={recipe.id}><h2>{recipe.name}</h2><ul>{recipe.ingredients.map(ingredient =><li key={ingredient}>{ingredient}</li>)}</ul></div>)}</div>);
}

这段代码是一个 React 组件,用于展示菜谱列表,包含了 React 中的核心概念(组件、JSX、列表渲染、key 属性等)。我们一步步拆解,确保每个细节都讲清楚:

1. 整体结构:一个 React 组件

// 导入外部数据
import { recipes } from './data.js';// 定义并导出一个名为 RecipeList 的组件
export default function RecipeList() {return (// JSX 结构:组件要渲染的内容<div>...</div>);
}
  • 组件RecipeList 是一个 “函数组件”(React 中最基础的组件形式),本质是一个返回 UI 结构的函数。
  • 导出export default 表示这个组件可以被其他文件导入使用(比如在 App 组件中引入 <RecipeList /> 来显示)。

2. 导入数据:import { recipes } from './data.js'

  • 从当前目录的 data.js 文件中,导入了一个名为 recipes 的数组(假设 data.js 里存储了菜谱数据,格式类似下面这样):
    // 假设 data.js 中的内容
    export const recipes = [{id: 1,name: "番茄炒蛋",ingredients: ["番茄", "鸡蛋", "盐", "糖"]},{id: 2,name: "凉拌黄瓜",ingredients: ["黄瓜", "蒜末", "醋", "生抽"]}
    ];
    
  • recipes 是一个包含多个 “菜谱对象” 的数组,每个对象有 id(唯一标识)、name(菜谱名称)、ingredients(食材数组)三个属性。

3. 返回的 JSX 结构:组件的 UI 内容

JSX 是 React 特有的语法,允许在 JavaScript 中直接写 HTML 标签,最终会被转换为浏览器能理解的 JavaScript 代码。

整个返回的结构可以拆分为三层:

第一层:最外层容器 <div>
<div><h1>菜谱</h1>{/* 这里会动态渲染菜谱列表 */}
</div>
  • 最外层必须有一个容器(这里用 <div>),因为 React 组件返回的 JSX 必须是 “单一根元素”(不能并列返回多个标签)。
  • <h1>菜谱</h1> 是静态标题,固定显示 “菜谱” 二字。
第二层:遍历 recipes 数组,渲染每个菜谱
{recipes.map(recipe =><div key={recipe.id}><h2>{recipe.name}</h2>{/* 这里会动态渲染当前菜谱的食材列表 */}</div>
)}

这部分是 “动态渲染列表” 的核心,用 map 方法遍历 recipes 数组,把每个菜谱对象转换成对应的 UI 元素:

  • recipes.map(...)map 遍历数组 recipes,每次遍历拿到一个元素 recipe(即单个菜谱对象,比如上面例子中的 “番茄炒蛋” 对象)。

  • 箭头函数 recipe => { ... }:作为 map 的回调函数,接收当前菜谱对象 recipe,并返回一个 JSX 结构(每个菜谱对应的 UI)。

  • key={recipe.id}:React 要求列表中的每个元素必须有唯一的 key 属性(用于优化渲染性能,避免重复创建 / 删除元素)。这里用 recipe.id 作为 key,因为 id 是每个菜谱的唯一标识(比如 1、2),符合 “唯一性” 和 “稳定性” 要求。

  • <h2>{recipe.name}</h2>:用 { } 嵌入 JavaScript 表达式,显示当前菜谱的名称(比如 “番茄炒蛋”)。{ } 是 JSX 中嵌入变量 / 表达式的语法。

第三层:遍历 ingredients 数组,渲染食材列表
<ul>{recipe.ingredients.map(ingredient =><li key={ingredient}>{ingredient}</li>)}
</ul>

每个菜谱对象里有 ingredients 数组(比如 ["番茄", "鸡蛋"]),这里再用一次 map 遍历这个数组,渲染食材列表:

  • recipe.ingredients.map(...):遍历当前菜谱的 ingredients 数组,每次拿到一个元素 ingredient(即单个食材,比如 “番茄”)。

  • key={ingredient}:同样需要 key,这里直接用食材名称作为 key(假设同一菜谱的食材不重复,满足唯一性)。如果食材可能重复(比如 “盐” 在多个步骤出现),更好的做法是给食材也加唯一 id(如 { id: 1, name: "盐" }),再用 key={ingredient.id}

  • <li>{ingredient}</li>:用 <li> 标签显示每个食材,{ingredient} 嵌入食材名称(比如 “鸡蛋”)。

4. 最终渲染效果

假设 data.js 中的 recipes 数组是前面举例的内容,那么这个组件会渲染出:

<div><h1>菜谱</h1><!-- 第一个菜谱 --><div><h2>番茄炒蛋</h2><ul><li>番茄</li><li>鸡蛋</li><li>盐</li><li>糖</li></ul></div><!-- 第二个菜谱 --><div><h2>凉拌黄瓜</h2><ul><li>黄瓜</li><li>蒜末</li><li>醋</li><li>生抽</li></ul></div>
</div>

核心知识点总结

  1. 函数组件function RecipeList() { return ... } 定义了一个可复用的 UI 组件。
  2. JSX 语法:允许在 JS 中写 HTML 标签,用 { } 嵌入变量 / 表达式。
  3. 列表渲染:用 array.map() 遍历数组,动态生成多个相同结构的 UI 元素。
  4. key 属性:列表元素必须有唯一 key,用于 React 优化渲染,通常用数据中的唯一 ID。
  5. 数据驱动 UI:UI 结构由 recipes 数组的数据决定,当数据变化时,UI 会自动更新(这是 React 的核心特性)。

如果 data.js 中的菜谱数据增加、删除或修改,这个组件会自动同步显示最新的内容,无需手动修改 UI 代码 —— 这就是 React “数据驱动” 的优势。

6 Fragment 语法

在 React 中,Fragment(片段) 是一种语法,用于在不添加额外 DOM 节点的前提下,将多个元素组合在一起。

作用

当组件需要返回多个并列的元素时,按照 JSX 规则,必须用一个父元素(如 <div>)包裹。但有时我们不想添加多余的 <div> 节点(避免影响 DOM 结构和样式),这时就可以用 Fragment 来 “包裹” 这些元素,同时不产生额外的 DOM 层级。

语法形式

1. 显式写法(<React.Fragment>
import React from 'react';function MyComponent() {return (<React.Fragment><h1>标题</h1><p>内容</p></React.Fragment>);
}
2. 简写语法(<> 和 </>

这是更常用的简洁写法,效果和 <React.Fragment> 完全一致:

function MyComponent() {return (<><h1>标题</h1><p>内容</p></>);
}

与普通容器的区别

场景使用 <div> 包裹使用 Fragment 包裹
DOM 结构会新增一个 <div> 节点无额外 DOM 节点
样式影响可能因 <div> 触发布局问题不影响原有样式结构
使用场景需要给多个元素加统一样式 / 逻辑时仅需组合元素,无额外 DOM 需求时

例如,在之前的菜谱列表中,如果不想给每个菜谱外层加 <div>,可以用 Fragment 优化:

{recipes.map(recipe => (<><h2 key={recipe.id}>{recipe.name}</h2><ul>{recipe.ingredients.map(ingredient =><li key={ingredient}>{ingredient}</li>)}</ul></>
))}

这样每个菜谱的 h2 和 ul 就不会被额外的 <div> 包裹,DOM 结构更纯净。

【这不是js的语法吗】

Fragment 并不是原生 JavaScript 的语法,而是 React 特有的语法扩展,专门用于解决 JSX 中 “多元素必须有唯一父节点” 的问题。

具体来说:

  • 原生 JavaScript 中并没有 <> 或 <React.Fragment> 这样的语法,它们是 React 团队为了简化 JSX 写法设计的。
  • JSX 本身也不是原生 JavaScript 语法(浏览器无法直接识别 <div> 这种在 JS 里写标签的形式),需要通过 Babel 等工具编译成普通 JS 代码才能运行。而 Fragment 作为 JSX 的一部分,自然也依赖 React 的编译处理。

举个编译后的例子你就明白了:

// 你写的 Fragment 代码
return <><h1>标题</h1><p>内容</p>
</>

会被 Babel 编译成 React 能处理的普通函数调用:

return React.createElement(React.Fragment,  // 注意这里:Fragment 本质是 React 提供的一个特殊组件null,React.createElement("h1", null, "标题"),React.createElement("p", null, "内容")
);

可以看到,<> 最终会被转换成 React 提供的 React.Fragment 组件 —— 这完全是 React 框架内部的机制,和原生 JavaScript 语法无关。

总结:Fragment 是 React 为了优化 JSX 结构设计的语法,属于 React 生态的一部分,而非原生 JavaScript 语法。它的存在是为了让开发者在写 JSX 时更灵活,同时避免多余的 DOM 节点。

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

相关文章:

  • 企业信息门户网站建设方案设计素材的网站
  • 如何将自己做的网站变成中文帮忙制作网页的公司
  • gpu driven:vello新执行流程
  • LangGraph的Agent长短时记忆的原理有什么区别,分别适用于什么业务场景
  • 定制网站开发的目的是什么做单位网站的公司吗
  • 做网站建立数据库自适应的网站模板
  • 路由硬盘做网站空间不中国城乡建中国城乡建设部网站
  • 电脑怎么做服务器 网站wordpress手机号网站
  • 跨境电商技术与运营双升级!亚马逊 / TikTok/Temu 本周新政解读,附卖家技术适配指南​
  • C++ 类的学习(七) 类的转换 和 嵌套类
  • C++进阶: 虚函数1-----继承中的灵魂
  • 软件协议使用应知应会
  • C语言进阶:深入探讨指针(一)
  • 网站备案 信息wordpress支付接口同步回调
  • 当 AI 开始书写历史:我们如何用 Gateone.ai 把“历史人物时间线”从学术幻想变成 SaaS 产品
  • 如何推广企业网站杭州物联网前十名公司
  • SQL Server
  • state machine diagrams用于需求分析阶段还是设计阶段
  • 【穿越Effective C++】Scott Meyers的《Effective C++》逻辑框架概要汇总--各条款是什么?为什么?怎么做?
  • 易旅游网站建设wap网站开发和自适应
  • 免费iOS加固方案指南
  • 登封快乐送餐在那个网站做的广告wordpress版本对应php版本
  • 云南网站建设一度科技网站团购活动页面怎么做
  • 电动自行车为何限速25公里每小时?——安全、法规与技术的平衡之道
  • 怎样用vs2017做网站长沙做网站要多少钱
  • 怎么学建设网站盐城企业建设网站
  • 长沙百度做网站多少钱wordpress页面模板目录文件
  • VLFM视觉语言基础模型使用指南
  • 口碑好的番禺网站建设开饰品店网站建设预算
  • 网站 设计 分辨率wordpress+制作首页模板下载