Appearance
JSX、组件与单向数据流
很多人第一次学 React,会把注意力放在“JSX 长得像 HTML”。
但 React 这一层真正要解决的,不是“页面怎么写得像模板”,而是:
- UI 怎么拆成可组合的组件
- UI 结构怎么用 JavaScript 描述
- 数据怎么从父组件流向子组件
- 页面逻辑为什么可以和视图结构组织在一起
这篇文章重点讲:
- JSX 到底是什么
- React Element 和组件是什么关系
- 函数组件在现代 React 里的定位
props和单向数据流为什么重要- 组件组合为什么比继承更常见
1. JSX 到底是什么
JSX 不是浏览器原生语法,也不是模板引擎本身。
JSX 是一种语法糖,用来把“组件树”和“UI 结构”写得更接近最终页面形态。
例如:
jsx
function WelcomeCard({ name }) {
return <h1>Hello, {name}</h1>;
}这段代码最终不会直接原样交给浏览器执行,而是会在编译阶段转成类似这样的调用:
js
function WelcomeCard({ name }) {
return React.createElement("h1", null, "Hello, ", name);
}🌟 所以 JSX 的核心价值不是“像 HTML”,而是 让 UI 结构、组件组合和数据插值能够自然地写在 JavaScript 里。
2. JSX 和 HTML 有什么本质区别
它们看起来很像,但不是一回事。
| 对比项 | JSX | HTML |
|---|---|---|
| 运行位置 | 编译后进入 JavaScript 运行时 | 浏览器原生直接解析 |
| 属性写法 | 更接近 JavaScript,例如 className、onClick | 更接近文档标记语言 |
| 表达式能力 | 可以直接嵌入 JavaScript 表达式 | 不能直接写 JavaScript 表达式 |
| 最终目标 | 生成 React Element | 表达静态文档结构 |
例如:
jsx
function UserInfo({ user }) {
const isVip = user.level === "VIP";
return (
<section className="user-card">
<h2>{user.name}</h2>
{isVip ? <span>VIP</span> : null}
</section>
);
}这段 JSX 最重要的点,是 UI 结构里直接混入了:
- 变量读取
- 条件判断
- 组件组合
也就是说,它不是“HTML 里插一点 JS”,而是“用 JavaScript 描述 UI”。
3. React Element 和组件是什么关系
这两个概念很容易混。
3.1 React Element 是什么
React Element 可以看成 一份轻量的 UI 描述对象。
它通常会记录:
- 这是哪种节点
- 有哪些 props
- 子节点是什么
JSX 写出来的,不是 DOM,也不是组件实例,而更像是“下一步该渲染成什么 UI”的描述。
3.2 组件是什么
组件是生成这份 UI 描述的组织单元。
在现代 React 里,更常见的就是函数组件:
jsx
function ProductCard({ product }) {
return (
<article>
<h3>{product.name}</h3>
<p>{product.price}</p>
</article>
);
}这个函数组件做的事情,本质上是:
- 接收输入
props - 根据输入返回一棵 React Element 树
🌟 把这层关系记住:组件负责组织 UI,React Element 负责描述 UI。
4. 为什么现代 React 以函数组件为主
当前 React 的主线已经明显转向函数组件。
主要原因是:
- 更贴近 JavaScript 函数式组织方式
- 更容易通过 Hook 复用状态逻辑
- 组合方式比类继承更自然
- 更适合和现代 React 的渲染模型一起理解
这不等于类组件完全没价值,而是 现代 React 的新能力和主流实践,几乎都围绕函数组件展开。
所以这套笔记也会以函数组件作为主线。
5. props 到底是什么
props 可以看成组件的输入。
它主要解决的是,让组件从外部拿到配置、数据和回调,而不是把一切写死在组件内部。
例如:
jsx
function Button({ type, disabled, children, onClick }) {
return (
<button className={`btn btn-${type}`} disabled={disabled} onClick={onClick}>
{children}
</button>
);
}这里的:
typedisabledchildrenonClick
都是外部传进来的输入。
props 最关键的边界是 只读。
也就是说:
- 组件可以使用它
- 组件不应该直接修改它
如果一个组件会自己改自己的输入,数据来源就会变得混乱。
6. 什么叫单向数据流
React 非常强调单向数据流。
它的核心含义是,数据通常从父组件流向子组件,更新动作通过回调再往上反馈。
例如:
jsx
function CounterPage() {
const [count, setCount] = useState(0);
return <Counter value={count} onIncrease={() => setCount(count + 1)} />;
}
function Counter({ value, onIncrease }) {
return <button onClick={onIncrease}>count: {value}</button>;
}这段代码里:
count从父组件传给子组件- 子组件不直接改
count - 子组件通过
onIncrease通知父组件去更新
这样做的最大价值是:
- 状态来源更清楚
- 依赖方向更稳定
- 调试和排查更容易
7. children 为什么很重要
很多人一开始只把 children 当成“插槽内容”。
它其实是 React 组件组合能力里非常核心的一部分。
例如:
jsx
function Card({ title, children }) {
return (
<section className="card">
<h3>{title}</h3>
<div className="card-body">{children}</div>
</section>
);
}使用时:
jsx
<Card title="订单信息">
<OrderSummary />
</Card>这里 Card 并不关心里面一定是什么组件,它只负责布局和结构容器。
这正是 React 很强调的思想,通过组合组装能力,而不是通过继承叠能力。
8. 为什么 React 更强调组合而不是继承
组件系统真正复杂起来之后,继承往往会带来:
- 层次关系越来越深
- 行为来源越来越难追踪
- 复用方式越来越僵硬
而组合更自然的做法是:
- 把布局抽成组件
- 把行为抽成 Hook
- 把数据通过 props 传入
- 把可变区域通过
children或插槽式 props 交给外部
工程上更常见的复用思路通常是:
- 组件组合
- 自定义 Hook
- 高阶组件或 render props 作为历史或特定场景方案
9. JSX 和组件层最常见的误区
9.1 以为 JSX 就是模板
不够准确。
它更像是 UI 的 JavaScript 表达方式。
9.2 以为组件只是为了拆文件
也不够。
组件真正重要的是:
- 抽象 UI 单元
- 建立输入输出边界
- 复用结构和行为组织方式
9.3 以为单向数据流只是“父传子”
也太浅了。
它真正重要的是,让状态的拥有者和更新入口都更清楚。
10. 一句话总结
React 在 JSX 和组件这一层最核心的设计,是用 JavaScript 描述 UI,用组件组织界面,再通过 props 和单向数据流建立稳定的数据边界。