❌ — "class"是JS保留字
// 规则3:style 接收对象而非字符串
样式
// 驼峰命名:fontSize, backgroundColor, gridColumn 等
// 规则4:单根节点或 Fragment
const Card = ({ title, children }) => (
<> {/* ✅ Fragment:不产生额外 DOM 节点 */}
{title}
{children}
>
);
```
> [!note] key 属性的唯一要求
> - `key` 只在数组上下文中有效——它是 React 的元数据,不会被传递给组件
> - 在自定义组件上使用 key 会报错:**key 只能在列表子元素上使用**
## Props 传递方式
```tsx
interface CardProps {
title: string;
className?: string;
children: React.ReactNode;
}
function Card({ title, className = "", children }: CardProps) {
return (
{title}
{children}
);
}
// 展开 props
const attrs = { className: "card", title: "详情" };
;
// 动态属性名
// 受控 props(父组件控制子组件内部 state)
// 函数作为 prop(常见于表单回调)
setQuery(q)} />
```
> [!question] 为什么 children 的类型是 React.ReactNode 而不是 JSX.Element?
> - `JSX.Element` 只代表 React 元素(如 ``、``)
> - `React.ReactNode` 包含更多可能:字符串、数字、Fragment、甚至 null/undefined
> - 💡 使用 `JSX.Element` 会报错当子元素是纯文本或数组时
## JSX 与模板引擎对比
```mermaid
graph LR
A[JSX] --> B["编译期检查"]
A --> C["完整的 JavaScript 能力"]
A --> D["类型安全(TS)"]
E["模板引擎 v-html/v-if"] --> F["运行时解析"]
E --> G["字符串插值 {{}}"]
E --> H["有限的 JS 表达式"]
style A fill:#61DAFB,color:#000
style E fill:#42B883,color:#fff
```
> [!tip] JSX 的核心优势
> 1. **强类型** — 配合 TypeScript 编译期拦截错误
> 2. **零额外语法** — 没有 {{}} / v-if / v-for 等新规则,一切在 JS 中
> 3. **JS 全能力** — 解构、spread、闭包、高阶函数随时可用
## JSX 渲染流程
```mermaid
sequenceDiagram
participant Dev as 开发者
participant Babel as Babel/TSX
participant React as React Runtime
participant VDOM as Fiber (虚拟 DOM)
participant Diff as Reconciler Diff
participant BM as Browser API
Dev->>Babel: 编写 JSX:Hello
Note over Dev,Babel: "编译期转换,非运行时"
Babel->>Babel: 转译成 createElement()
Babel->>React: React.createElement("h1", null, "Hello")
Note over React: 返回 VDOM Plain Object
React->>VDOM: 创建/更新 Fiber 树
VDOM->>Diff: Diff 算法比较新旧树
Diff->>Diff: 找出最小变更集
Diff->>BM: patch 真实 DOM
Note over BM: "批量更新,一次 Reflow/Repaint"
```
> [!note] 一句话总结渲染流程
> JSX → `createElement()` → VDOM → **Diff** → patch 真实 DOM
>
> JSX 的每次重新渲染都经历完整的 Diff 过程——这也是为什么理解 key 的作用至关重要。