ReactUI组件
定义组件
组件,即应用程序中可复用的UI元素.React组件是一段可以任意添加标签进行扩展的JavaScript函数.
定义组件的方法:
- 定义函数:使用
function Profile(){}定义名为Profile的JavaScript函数.组件的名称必须以大写字母开头. - 返回JSX:组件函数必须返回一个JSX元素,它描述了组件的UI结构.可以返回单个元素,也可以返回包含多个元素的片段.如果return和标签不在同一行,需要用括号括起来.如果返回多个元素,需要用一个父元素包裹起来,如
<div>...</div>或`<>…</> - 导出组件:使用
export关键字将组件导出,以便在其他文件中导入和使用.可以使用默认导出(export default Profile)或命名导出(export { Profile }).
使用组件
类似HTML标签,在JSX中使用组件.组件标签必须以大写字母开头区分于HTML标签.
jsx组件必需使用闭合标签,即使组件没有子元素,也必须使用自闭合标签
<Profile />.
组件嵌套
组件可以嵌套使用,即在一个组件的JSX中使用另一个组件.这允许创建复杂的UI结构.
但是不允许在组件内部定义另一个组件.应该在文件的顶层定义所有组件.
拆分组件–复用与维护
将组件拆分为多个小组件,每个组件负责特定的功能或UI部分.这有助于提高代码的复用性和可维护性.
该如何拆分组件,详见设计模式相关博客
拆分组件的步骤:
- 创建一个新的JS文件来存放该组件.
- 导出该文件中的函数组件(可以使用默认导出或具名导出).
- 在需要使用该组件的文件中导入它(可以使用默认导入或具名导入).
组件导入导出详解
一个文件里有且仅有一个默认导出,但可以有多个具名导出.
| 语法 | 导出语句 | 导入语句 |
|---|---|---|
| 默认导出 | export default function ComponentName() {}或export default ComponentName; | import ComponentName from './ComponentFile'; |
| 具名导出 | export function ComponentName() {} 或 export { ComponentName }; | import { ComponentName } from './ComponentFile'; |
当使用默认导入时,可以在import之后进行任意命名.(但是不推荐) 而具名导入必须使用与导出时相同的名称.
通常,文件中仅包含一个组件时,人们会选择默认导出,而当文件中包含多个组件或某个值需要导出时,则会选择具名导出.
什么是JSX
JSX 是 JavaScript 语法扩展,可以让你在 JavaScript 文件中书写类似 HTML 的标签。
为什么要使用 JSX?因为它使得定义和构建用户界面变得更加直观和简洁。通过 JSX,你可以直接在 JavaScript 代码中描述 UI 结构,而不需要使用繁琐的
React.createElement方法。
JSX规则
只能返回一个根元素:如果需要返回多个元素,必须用一个父元素包裹起来,如
<div>...</div>或<>...</>.(这个空标签被称作 Fragment。React Fragment 允许你将子元素分组,而不会在 HTML 结构中添加额外节点。)标签必需闭合:即使标签没有子元素,也必须使用自闭合标签
<img />或<Profile />.使用驼峰式命名法给大部分属性命名:JSX 最终会被转化为 JavaScript,而 JSX 中的属性也会变成 JavaScript 对象中的键值对。在你自己的组件中,经常会遇到需要用变量的方式读取这些属性的时候。但 JavaScript 对变量的命名有限制。例如,变量名称不能包含 - 符号或者像 class 这样的保留字。这就是为什么在 React 中,大部分 HTML 和 SVG 属性都用驼峰式命名法表示。例如,需要用 strokeWidth 代替 stroke-width。由于 class 是一个保留字,所以在 React 中需要用 className 来代替。
在JSX中通过{}嵌入js
使用场景:
用作JSX标签内的文本:
<h1>{name}'s To Do List</h1>是有效的,但是<{tag}>Gregorio Y. Zara's To Do List</{tag}>无效。用作紧跟在 = 符号后的 属性:
src={avatar}会读取 avatar 变量,但是src="{avatar}"只会传一个字符串{avatar}。
双层大括号:JSX中的css和对象
在 JSX 中,双大括号通常用于两种主要场景: 内联样式:在 JSX 中,内联样式是通过一个 JavaScript 对象来定义的。外层的大括号 {} 用于嵌入 JavaScript 表达式,而内层的大括号 {} 则表示一个对象字面量。例如:
1
return <div style={{color: 'blue', backgroundColor: 'lightgray', padding: '10px'}}>This is a styled div!</div>;
内联 style 属性 使用驼峰命名法编写。例如,HTML
<ul style="background-color: black"> 在你的组件里应该写成 <ul style={{ backgroundColor: 'black' }}>。
嵌套对象:有时你可能需要在 JSX 中传递一个对象作为属性值。在这种情况下,外层的大括号 {} 用于嵌入 JavaScript 表达式,而内层的大括号 {} 则表示一个对象字面量。例如:
1
2
3
4
5
6
const user
= {
name: 'Alice',
age: 30
};
return <UserProfile user={{...user, location: 'New York'}} />;
使用Props向组件传递数据
Props (属性) 是 React 组件的输入参数,用于向组件传递数据和配置选项.它们类似于函数的参数,但用于组件.可以通过它们传递任何类型的数据,包括字符串、数字、布尔值、对象、数组和函数.
定义和使用Props
在组件定义中,通过在函数参数中添加一个名为props的参数来接收传递给组件的属性.也可以使用解构赋值来直接提取特定的属性.两种定义是等价的,示例:
1
2
3
4
5
function Greeting(props) {
}
// 或者使用解构赋值
function Greeting({ name, age }) {
}
Props默认值
可以在参数后面写=和默认值来进行结构
1
2
function Greeting({ name = 'Guest', age = 18 }) {
}
默认值仅在缺少该属性时或被赋值为undefined时使用.
Props变化
Props是只读的,组件不能修改它们.如果需要在组件内部管理状态,应该使用State.
将JSX做为Props传递
可以将JSX元素作为Props传递给组件,以实现更复杂的UI结构.示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import Avatar from './Avatar.js';
function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}
export default function Profile() {
return (
<Card>
<Avatar
size={100}
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
/>
</Card>
);
}
条件渲染
选择性返回JSX表达式
可以使用条件语句(如if-else)来选择性地返回不同的JSX表达式.示例:
1
2
3
4
5
6
7
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
} else {
return <h1>Please sign up.</h1>;
}
}
使用逻辑与运算符
可以使用逻辑与运算符(&&)来简化条件渲染.如果条件为真,则渲染后面的表达式;否则不渲染任何内容.示例:
1
2
3
4
5
6
7
8
9
10
function Mailbox({ unreadMessages }) {
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>You have {unreadMessages.length} unread messages.</h2>
}
</div>
);
}
注意:切勿将数字放在&&左侧.JavaScript 会自动将左侧的值转换成布尔类型以判断条件成立与否。然而,如果左侧是 0,整个表达式将变成左侧的值(0),React 此时则会渲染 0 而不是不进行渲染。
使用三目运算符
1
2
3
4
5
function Greeting({ isLoggedIn }) {
return (
<h1>{isLoggedIn ? 'Welcome back!' : 'Please sign up.'}</h1>
);
}
渲染列表
从数组中渲染数据
可以使用JavaScript的map()方法来遍历数组并为每个元素返回一个JSX表达式.示例:
1
2
3
4
5
6
7
8
9
function NumberList({ numbers }) {
return (
<ul>
{numbers.map((number) =>
<li key={number.toString()}>{number}</li>
)}
</ul>
);
}
如果需要筛选数据,可以在
map()之前使用filter()方法.
使用key属性
在渲染列表时,每个元素都应该有一个唯一的key属性.这有助于React识别哪些元素发生了变化、添加或删除,从而提高渲染性能.通常使用数组元素的唯一标识符(如ID)作为key.如果没有唯一标识符,可以使用数组索引,但不推荐这样做,因为它可能导致渲染问题.
用作 key 的值应该在数据中提前就准备好,而不是在运行时才随手生成:
1
<li key={number.toString()}>{number}</li>
为每个列表项显示多个DOM节点
如果需要为每个列表项显示多个DOM节点,可以使用React.Fragment或<div>将它们包裹起来.示例:
1
2
3
4
5
6
7
8
9
10
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
如何设定key
- 来自数据的唯一标识符(如ID):如果你的数据是从数据库中获取的,那你可以直接使用数据表中的主键,因为它们天然具有唯一性。
- 本地产生数据: 如果你数据的产生和保存都在本地(例如笔记软件里的笔记),那么你可以使用一个自增计数器,crypto.randomUUID() 或者一个类似 uuid 的库来生成 key。
Key需要满足的条件
- 唯一性: key 必须在同一层级的兄弟节点中是唯一的,以便 React 能够正确识别和管理这些节点。(不要求全局唯一)
- 稳定性: key 的值应该是稳定的,不应该在组件的生命周期中改变。使用数组索引作为 key 是不推荐的,因为它可能导致渲染问题。
保持组件纯粹
React 组件应该是纯函数,即相同的输入(Props)总是返回相同的输出(JSX).避免在组件中使用副作用(如修改全局变量或DOM),以确保组件的可预测性和可测试性.
React 假设你编写的所有组件都是纯函数。