nodejs 019: React组件 JSX基础语法规则
- 注:本文为JSX基础语法规则总结,除一二级标题外的大部分内容由LLM生成
JSX
(JavaScript XML)是一种语法扩展,主要用于 React 项目。它让我们可以在 JavaScript 中直接编写类似 HTML 的代码,简化了定义 UI 组件的过程( JSX有点像JAVA的JSP)。- JSX 将标记和逻辑紧密结合,使代码更具可读性和可维护性。JSX 是一个由 React 引入的概念,现在在其他框架(如 Vue 3)中也得到了应用。
Ⅰ.JSX 的基本概念
-
类似 HTML 的语法
const element = <h1>Hello, world!</h1>;
-
在组件中使用 JSX
JSX 最常用于定义 React 组件的结构。React 组件是一个返回 JSX 的函数或类,可以将复杂的 UI 拆分成独立、可复用的组件。例如:function Welcome(props) { return <h1>Hello, {props.name}</h1>; }
JSX 的特点和优势
-
内嵌表达式:在 JSX 中可以嵌入任何 JavaScript 表达式,只需将其包裹在
{}
中。const name = 'React'; const element = <h1>Hello, {name}</h1>;
-
支持条件渲染:可以使用 JavaScript 的条件运算符进行条件渲染。
function Greeting(props) { const isLoggedIn = props.isLoggedIn; return ( <div> {isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign up.</h1>} </div> ); }
-
支持循环渲染:可以通过
map
等方法来渲染列表。const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li key={number.toString()}>{number}</li> ); return <ul>{listItems}</ul>;
Ⅱ.className
-
className
是 JSX 中用于指定 HTML 元素 CSS 类的属性。在标准的 HTML 中,我们使用class
属性来指定样式,但在 JSX 中,因为class
是 JavaScript 的保留字,所以改成了className
。 -
在 JSX 中设置
className
非常简单,类似于 HTML 的class
,只需在元素上添加className
属性并赋值一个字符串即可:
function MyComponent() {
return <div className="my-class">Hello, World!</div>;
}
-
动态设置
className
; -
- 三元运算符
使用三元运算符来根据条件设置 className
:
function MyComponent({ isActive }) {
return <div className={isActive ? "active" : "inactive"}>Hello, World!</div>;
}
-
- 模板字符串
如果需要组合多个类,可以使用模板字符串(ES6 的字符串模板语法):
function MyComponent({ isActive, isLarge }) {
return <div className={`${isActive ? "active" : ""} ${isLarge ? "large" : ""}`}>Hello, World!</div>;
}
-
- 使用条件库
classnames
- 使用条件库
在大型项目中管理多个条件类时,可以使用 classnames
库。它简化了 className
的管理,让代码更加清晰易读:
npm install classnames
使用示例:
import classNames from 'classnames';
function MyComponent({ isActive, isLarge }) {
const classes = classNames({
active: isActive,
large: isLarge,
'extra-class': true,
});
return <div className={classes}>Hello, World!</div>;
}
在上面的代码中,classnames
自动生成类名字符串。如果 isActive
和 isLarge
为 true
,生成的 className
会是 active large extra-class
。
通过样式文件使用 className
通常,我们会在组件中用 className
连接 CSS 样式表,方法是将样式写在 CSS 文件中,然后通过 className
引用。
使用 CSS 模块
在 React 中也可以使用 CSS 模块,这样可以避免样式的全局污染。CSS 模块会自动生成独特的类名,以保证样式只在当前组件中有效。
-
首先,创建一个 CSS 模块文件,比如
MyComponent.module.css
:/* MyComponent.module.css */ .active { color: red; } .large { font-size: 2em; }
-
在组件中导入这个 CSS 模块并应用样式:
import styles from './MyComponent.module.css'; function MyComponent({ isActive, isLarge }) { return ( <div className={`${isActive ? styles.active : ""} ${isLarge ? styles.large : ""}`}> Hello, World! </div> ); }
使用 className
,可以轻松地将 CSS 应用到 JSX 元素中,并且能动态地控制它们。
Ⅲ.首字母大小写和自定义组件
在 React 中,组件的命名约定非常重要,尤其是当涉及到首字母大小写的使用和自定义组件的区分时。以下是相关的细节:
1. 首字母大小写的规则
React 通过组件名称的首字母大小写来区分 HTML 元素和自定义 React 组件:
-
首字母大写:React 认为这是一个自定义组件。自定义组件通常是函数或类,并且在 JSX 中渲染时,React 会调用它返回的 JSX 结构。例如,
<MyComponent />
被认为是一个 React 组件。function MyComponent() { return <div>Hello from MyComponent!</div>; } function App() { return <MyComponent />; }
-
首字母小写:React 会将其当作标准 HTML 元素(如
<div>
或<span>
)来渲染。如果在 JSX 中写<mycomponent />
,React 会尝试将其当作 HTML 标签而不是组件,导致渲染失败或产生警告。
2. 自定义组件的编写
在 React 中编写自定义组件时,我们通常遵循 PascalCase(即每个单词的首字母大写)命名规范,这样可以避免和 HTML 标签冲突,并符合 React 社区的常规习惯。例如:
function UserProfile() {
return <div>User Profile Component</div>;
}
使用自定义组件时可以传递 props
:
function UserProfile({ name }) {
return <div>Hello, {name}!</div>;
}
function App() {
return <UserProfile name="Alice" />;
}
3. 动态渲染自定义组件
有时,我们可能需要动态选择组件进行渲染。可以通过对象映射来实现动态组件的选择,例如:
function Home() {
return <div>Home Component</div>;
}
function About() {
return <div>About Component</div>;
}
const components = {
home: Home,
about: About,
};
function App({ componentName }) {
const Component = components[componentName];
return Component ? <Component /> : <div>Component Not Found</div>;
}
// 使用示例
<App componentName="home" />; // 渲染 Home 组件
4. 使用小写首字母的自定义标签(非 React 推荐)
尽管不推荐,但在某些情况下可能需要使用小写的自定义标签。可以通过直接创建元素来实现。React 提供了 React.createElement
函数,可以用来创建 React 元素而不依赖 JSX。例如:
function app() {
return React.createElement("custom-element", { id: "myId" }, "Hello!");
}
不过,为了遵循 React 社区的最佳实践,尽量避免这种方式。
5. CSS 组件样式约定
对于自定义组件的样式,可以使用对应的 className
,配合 CSS 文件或者 CSS 模块。CSS 模块可以使样式在组件间隔离,避免样式冲突。
// MyComponent.module.css
.myComponent {
color: blue;
}
// MyComponent.jsx
import styles from './MyComponent.module.css';
function MyComponent() {
return <div className={styles.myComponent}>Styled Component</div>;
}
总结
- 自定义组件的名称应始终以大写字母开头,以便 React 能够正确识别它们。
- 可以使用
props
为组件传递数据,保持组件的可复用性。 - 动态选择和渲染自定义组件时,可以用对象映射来选择特定组件。
- 使用 CSS 模块或 className 控制组件样式,保持组件之间的样式隔离。
Ⅳ.style要写成对象的形式
在 JSX 中,style
属性需要写成 JavaScript 对象的形式,而不是普通的字符串或 CSS 样式规则。每个 CSS 属性都需要用 JavaScript 对象的语法表示。
基本写法
在 React 中使用 style
属性时,应该使用 驼峰命名(camelCase),因为在 JavaScript 中 -
是无效字符。
例如,background-color
需要写成 backgroundColor
:
function MyComponent() {
return (
<div style={{ backgroundColor: 'blue', color: 'white', padding: '10px' }}>
Hello, World!
</div>
);
}
上面的 style
属性接收一个 JavaScript 对象,其中每个 CSS 属性都以键值对的形式表示。
动态设置样式
你可以在 style
对象中动态设置样式属性,通过变量或者表达式来实现。例如,可以根据组件的状态改变样式:
function MyComponent({ isActive }) {
return (
<div
style={{
color: isActive ? 'green' : 'gray',
fontWeight: isActive ? 'bold' : 'normal',
}}
>
Status: {isActive ? 'Active' : 'Inactive'}
</div>
);
}
多个样式对象的组合
如果有多个样式对象,可以通过 JavaScript 的扩展运算符 {...}
或 Object.assign
合并样式:
const baseStyle = {
color: 'white',
fontSize: '16px',
};
const activeStyle = {
color: 'green',
fontWeight: 'bold',
};
function MyComponent({ isActive }) {
return (
<div style={{ ...baseStyle, ...(isActive ? activeStyle : {}) }}>
Hello, World!
</div>
);
}
示例:样式对象与内联样式
const containerStyle = {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
backgroundColor: '#282c34',
};
function App() {
return (
<div style={containerStyle}>
<h1 style={{ color: 'white', fontSize: '2em' }}>Welcome to My App</h1>
</div>
);
}
在这个示例中,containerStyle
是一个样式对象,并且在 App
组件中通过 style={containerStyle}
赋给 div
标签;h1
的样式则直接写在内联 style
中。
注意事项
- 单位:数值型的 CSS 属性(如
width
,height
,fontSize
)通常不需要单位,会自动以像素 (px
) 处理。例如:fontSize: 20
表示20px
。 - 嵌套样式:不能在
style
对象中直接嵌套选择器,如:hover
或@media
,这些需要通过 CSS 文件或 CSS-in-JS 解决方案(如styled-components
)来实现。
使用对象形式的 style
属性可以更灵活地实现样式的动态更新,也能充分利用 JavaScript 的表达能力。
Ⅴ.监听事件
1. 添加事件监听器
- 在 React 中,事件监听器使用 camelCase 形式,比如
onClick
、onMouseEnter
等。事件处理函数通常是一个箭头函数或组件方法。
示例:一个按钮的点击事件
function App() {
function handleClick() {
console.log("Button clicked!");
}
return <button onClick={handleClick}>Click me</button>;
}
- 注:
不要写函数的执行结果
2. 事件对象
React 中的事件处理函数会接收到一个合成事件(SyntheticEvent
),它是对原生事件的封装,与原生 DOM 事件 API 类似且跨浏览器兼容。
示例:使用事件对象
function App() {
function handleClick(event) {
console.log("Button clicked at position:", event.clientX, event.clientY);
}
return <button onClick={handleClick}>Click me</button>;
}
在这个示例中,event.clientX
和 event.clientY
是点击事件发生的鼠标位置。
3. 使用箭头函数传递参数
如果需要给事件处理函数传递参数,可以使用箭头函数。
示例:传递自定义参数
function App() {
function handleClick(name) {
console.log(`Hello, ${name}!`);
}
return <button onClick={() => handleClick("Alice")}>Greet Alice</button>;
}
这里我们用箭头函数 () => handleClick("Alice")
将参数传递给 handleClick
。
4. 事件的常用类型
React 支持大多数常见的 DOM 事件,包括但不限于:
- 鼠标事件:
onClick
,onDoubleClick
,onMouseEnter
,onMouseLeave
,onMouseMove
- 键盘事件:
onKeyDown
,onKeyUp
,onKeyPress
- 表单事件:
onChange
,onSubmit
,onFocus
,onBlur
- 窗口事件:
onResize
,onScroll
- 剪贴板事件:
onCopy
,onPaste
import React, { useState } from "react";
import type { MouseEvent } from "react";
function MouseTracker() {
const [position, setPosition] = useState({ x: 0, y: 0 });
// 使用 MouseEvent 类型为事件处理函数添加类型定义
function handleMouseMove(event: MouseEvent<HTMLDivElement>) {
setPosition({
x: event.clientX,
y: event.clientY,
});
}
return (
<div
onMouseMove={handleMouseMove}
style={{
width: "400px",
height: "300px",
border: "2px solid black",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<p>Mouse Position: ({position.x}, {position.y})</p>
</div>
);
}
export default MouseTracker;
5. 阻止默认行为和事件传播
可以通过 event.preventDefault()
和 event.stopPropagation()
控制事件的行为。
示例:阻止表单提交的默认刷新行为
function App() {
function handleSubmit(event) {
event.preventDefault();
console.log("Form submitted!");
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
在这个示例中,通过 event.preventDefault()
阻止了表单的默认提交行为。
6. 事件解绑
在 React 中,通常不需要手动解绑事件。React 的合成事件系统会自动管理事件的绑定和解绑,以确保性能和资源使用。
7. 使用 useEffect
监听全局事件
如果需要监听全局事件(例如 window
或 document
的事件),可以使用 useEffect
钩子在组件挂载时添加事件监听,并在卸载时移除。
import { useEffect } from 'react';
function App() {
useEffect(() => {
function handleResize() {
console.log("Window resized!");
}
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return <div>Resize the window to see the effect!</div>;
}
在这里,我们使用 useEffect
监听 window
的 resize
事件,并在组件卸载时清理该事件监听器。
Ⅵ.{}和判断
-
{}中不能放置大段js代码,需要通过&& 和 三目运算符进行条件判断
错误示例:
// 这会导致错误 return ( <div> {if (isLoggedIn) { <p>Welcome back!</p> }} </div> );
正确示例:
let message; if (isLoggedIn) { message = <p>Welcome back!</p>; } else { message = <p>Please log in.</p>; } return <div>{message}</div>;
使用 &&
运算符
&&
运算符通常用来在条件为 true
时渲染内容,否则什么都不显示。
const isLoggedIn = true;
return (
<div>
{isLoggedIn && <p>Welcome back!</p>}
</div>
);
解释:
- 如果
isLoggedIn
为true
,则渲染<p>Welcome back!</p>
。 - 如果
isLoggedIn
为false
,则什么也不渲染。
使用三目运算符 ? :
三目运算符允许你根据条件返回不同的内容。
const isLoggedIn = true;
return (
<div>
{isLoggedIn ? <p>Welcome back!</p> : <p>Please log in.</p>}
</div>
);
解释:
- 如果
isLoggedIn
为true
,则渲染<p>Welcome back!</p>
。 - 如果
isLoggedIn
为false
,则渲染<p>Please log in.</p>
。
通过使用 &&
和 ? :
运算符,React 组件能够以简洁的方式实现条件渲染。
Ⅶ.{}和循环
在 React JSX 中,{}
用于嵌入 JavaScript 表达式,但它不能直接包含 for
循环语句,因为 for
是 语句 而不是 表达式。因此,如果想在 React 中循环渲染多个元素,需要使用 JavaScript 的 数组方法(如 map()
)来实现。
使用 map() 渲染列表
const items = ["Apple", "Banana", "Cherry"];
function ItemList() {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
export default ItemList;
解释:
- 使用
items.map()
遍历items
数组,并为每个item
返回一个<li>
元素。 key
属性用于唯一标识每个元素,帮助 React 识别列表中的元素变化,以提高渲染效率。
在组件中使用循环
如果你确实需要使用 for
循环,可以在 JSX 之外创建一个变量来存储结果,并在 JSX 中引用该变量。
const items = ["Apple", "Banana", "Cherry"];
function ItemList() {
const listItems = [];
for (let i = 0; i < items.length; i++) {
listItems.push(<li key={i}>{items[i]}</li>);
}
return <ul>{listItems}</ul>;
}
export default ItemList;
解释:
- 先使用
for
循环将<li>
元素推入listItems
数组。 - 然后在 JSX 中使用
{listItems}
渲染列表。
JSX语法注意项目:
- 属性命名:在 JSX 中,
class
用className
替代,for
用htmlFor
替代,以避免与 JavaScript 保留字冲突。
// 正确的写法(React JSX)
<label htmlFor="username">Username:</label>
<input id="username" type="text" />
// 错误的写法
<label for="username">Username:</label>
<input id="username" type="text" />
- JSX 必须封闭标签:如果标签没有内容,必须使用自闭合形式
<br />
,否则会报错。 - 每个JSX片段只能有一个根节点 :
function MyComponent() {
return (
<>
<div>Element 1</div>
<div>Element 2</div>
</>
);
}