React 从入门到生产(一):JSX 与组件思维

React 从入门到生产(一):JSX 与组件思维

创作者: Yardon | GitHub: github.com/YardonYan | 版本: v1.0 |



开篇:为什么会有 React

2013 年,Facebook 的工程师们遇到了一个棘手的问题------他们的网站变得越来越复杂,页面上的状态(比如未读消息数、通知小红点、聊天窗口是否打开)像一团乱麻一样纠缠在一起。改一个地方,另一个看似不相关的地方就崩了。

这就是所谓的 "状态同步噩梦"

想象一下你在餐厅点菜。传统方式(jQuery 时代)就像你跟服务员说了要换一道菜,然后服务员得跑去告诉厨师、改账单、更新库存------而且所有这些都靠服务员手动跑来跑去,漏掉一步就出问题。

React 的方案是:「你只需要告诉我你想要的最终状态,我来负责把页面变成那个样子。」

这句话是理解 React 的核心。你不需要手动操作 DOM、不需要一步步告诉浏览器"先找到这个元素,然后改它的文字,再改它的样式"。你只需要声明:这个组件在某个状态下应该长什么样


JSX:把 HTML 写进 JavaScript 的魔法

这不是字符串,也不是 HTML

第一次看到 JSX 的人通常会有两个疑问:

"为什么要把 HTML 写到 JavaScript 里,这不是违反了关注点分离原则吗?"

"这语法到底是不是合法的 JavaScript?"

第二个问题好回答:JSX 不是原生 JavaScript 。浏览器不认识 <div>Hello</div> 这种写在 .js 文件里的东西。但是在打包阶段,Babel 或 TypeScript 编译器会把它翻译成标准的 JavaScript 函数调用。

比如你写的:

jsx 复制代码
const element = <h1 className="greeting">Hello, world!</h1>;

编译后大概变成:

javascript 复制代码
const element = React.createElement(
  'h1',
  { className: 'greeting' },
  'Hello, world!'
);

所以 JSX 本质上是 React.createElement() 的语法糖。理解这一点很重要------它帮你解释了为什么 JSX 表达式可以赋值给变量、可以在 if 语句里用、可以作为函数的返回值。

JSX 的几个基本规则

规则 1:必须有一个根元素

jsx 复制代码
// ❌ 不行------两个根元素
return (
  <h1>标题</h1>
  <p>内容</p>
);

// ✅ 用 Fragment(空标签)包裹
return (
  <>
    <h1>标题</h1>
    <p>内容</p>
  </>
);

<>...</> 是一种简写,等价于 <React.Fragment>...</React.Fragment>。它不会在 DOM 里真正创建一个节点。这就像用一根透明的线把两串珍珠穿在一起------线上只有珠子,线本身是看不见的。

规则 2:JavaScript 表达式用花括号

jsx 复制代码
const name = 'Yardon';
const user = { firstName: 'Yardon', lastName: 'Yan' };

// ✅ 花括号里可以放任何 JavaScript 表达式
<h1>Hello, {name}</h1>
<p>计算结果:{1 + 2 + 3}</p>
<span>{user.firstName} {user.lastName}</span>

// ❌ 但不能放语句
// <div>{if (true) { ... }}</div>  // 这是语句,不是表达式

规则 3:className 而非 class,htmlFor 而非 for

jsx 复制代码
// ❌ class 是 JavaScript 的保留关键字
<div class="container">

// ✅
<div className="container">
<label htmlFor="email">邮箱</label>

规则 4:自闭合标签必须闭合

jsx 复制代码
// ❌ HTML 里可以偷懒
<img src="avatar.png">
<br>

// ✅ JSX 里必须闭合
<img src="avatar.png" />
<br />

组件的本质:乐高积木思维

React 里最重要的概念就是组件。

组件 = 一个返回 UI 描述的函数

就这么简单。一个 React 组件就是一个 JavaScript 函数,它接收一些参数(props),返回一段 UI 描述(JSX)。

复制代码
输入(Props)→ 组件函数 → 输出(JSX)

就像乐高积木------每一块积木有自己的形状(UI)和连接点(Props),你可以把许多块积木拼在一起搭出一整座城堡。而且如果某一块坏了,你只需要替换那块积木,不用推倒整座城堡。

来看看一个简单的组件长什么样:

jsx 复制代码
// UserCard.jsx
function UserCard({ name, role, avatar }) {
  return (
    <div className="user-card">
      <img src={avatar} alt={name} />
      <h3>{name}</h3>
      <span className="role-badge">{role}</span>
    </div>
  );
}

这个组件就像一块蓝色的 2×4 积木------它有自己的外形,有连接点(name, role, avatar),可以嵌入到任何地方。


函数组件 vs 类组件:历史的选择

如果你去看 2018 年之前的 React 教程,你会发现满屏的 classthis

javascript 复制代码
// 类组件(旧)
class Welcome extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

但从 React 16.8 引入 Hooks 之后,函数组件成为了唯一推荐的方式。原因很简单:

  1. 代码量少很多------同样的功能,函数组件代码量通常是类组件的 60%
  2. 没有 this 的困惑 ------this 在 JavaScript 里是出了名的坑,函数组件里根本不用管它
  3. 逻辑复用更方便------Hooks 让"状态逻辑"可以抽出来到处用,这是类组件做不到的

2026 年你应该只写函数组件。如果你的项目里还有类组件,那是技术债,该还了。

jsx 复制代码
// 函数组件(现代)
function Welcome({ name }) {
  return <h1>Hello, {name}</h1>;
}

Props:组件之间的对话方式

Props(properties 的缩写)是 React 的神经系统。父组件通过 props 把数据传给子组件,就像你通过电话线把声音传到另一端。

Props 是只读的

这是 React 的铁律:组件绝不能修改自己的 props。

jsx 复制代码
function Greeting({ name }) {
  // ❌ 绝对不要这样做!
  // name = '修改后的名字';

  return <h1>Hello, {name}</h1>;
}

为什么?因为 React 的渲染模型建立在纯函数的概念之上。同样的输入(props),必须产生同样的输出(UI)。如果组件可以修改 props,整个「声明式」范式就崩塌了------你会回到手动追踪状态变化的地狱。

可以把 props 想象成你在餐厅点的菜单。你告诉服务员(父组件)你要什么,厨房(子组件)按照你的菜单做菜,但厨房不会修改你的菜单内容。

默认 Props

jsx 复制代码
function Button({ text = '点击', size = 'md', disabled = false }) {
  return (
    <button
      className={`btn btn-${size}`}
      disabled={disabled}
    >
      {text}
    </button>
  );
}

// 不传 text 时默认显示「点击」
<Button size="lg" />

// 传了就覆盖
<Button text="提交表单" size="sm" />

组件拆分原则:什么时候该拆

初学者常犯两个错误:要么一个组件写成 500 行的「巨无霸」,要么把每个 <div> 都拆成独立组件。

判断标准其实很简单,问自己三个问题:

问题 1:这部分会重复出现吗?

如果你发现自己在复制粘贴同一段 JSX,那它就应该被抽成一个组件。比如博客文章卡片、用户头像、评分星星。

jsx 复制代码
// 出现三次了------该拆!
{users.map(user => (
  <div className="user-card">
    <img src={user.avatar} />
    <span>{user.name}</span>
  </div>
))}

// 拆出来:
<UserCard user={user} />

问题 2:这部分有独立的逻辑吗?

如果一段代码有自己的状态(useState)、自己的副作用(useEffect)、自己的事件处理------它很可能值得独立成一个组件。

问题 3:你看这个组件时,需要滚动屏幕吗?

一个朴素的指标:如果组件代码超过 150 行,99% 的情况下它应该被拆分。这不是教条,而是------当一个组件长到你需要在编辑器里上下翻页时,理解它的心智负担已经超标了。

复制代码
拆分原则速查表:

┌────────────────┬──────────────────┐
│  条件           │  行动             │
├────────────────┼──────────────────┤
│ 相同 JSX 出现 3+ 次 │ 抽成独立组件        │
│ 有自己的 state      │ 抽成独立组件        │
│ 超过 150 行         │ 拆分为 2-3 个子组件  │
│ 逻辑可以被复用      │ 抽成独立组件        │
│ 只有一个 <div>     │ 不用拆,保持简单     │
└────────────────┴──────────────────┘

实战:搭建第一个 React 应用

用 Vite 创建一个 React 项目(2026 年,Vite 已经是前端事实标准):

bash 复制代码
# 创建项目
npm create vite@latest my-first-react -- --template react

# 进入目录
cd my-first-react

# 安装依赖
npm install

# 启动开发服务器
npm run dev

打开 src/App.jsx,把它替换为你的第一个组件:

jsx 复制代码
function App() {
  const skills = ['React', 'TypeScript', 'Node.js', 'Python'];

  return (
    <div className="app">
      <header>
        <h1>👋 你好,我是 Yardon</h1>
        <p>一个正在学习 React 的开发者</p>
      </header>

      <main>
        <h2>我的技术栈</h2>
        <ul>
          {skills.map(skill => (
            <li key={skill}>{skill}</li>
          ))}
        </ul>
      </main>

      <footer>
        <p>© 2026 Yardon. All rights reserved.</p>
      </footer>
    </div>
  );
}

export default App;

刷新浏览器,你应该看到一个简洁的个人页。是的,React 就是这么开始的------从最简单的组件起步,一步步搭建起复杂的应用。


本章小结

概念 一句话总结
JSX JavaScript 的语法扩展,让你用类似 HTML 的语法描述 UI,编译为 createElement()
组件 返回 UI 描述的函数,像乐高积木一样可组合
函数组件 2026 年唯一推荐的组件写法,Hooks 赋予了完整能力
Props 父组件传递给子组件的只读数据,是组件间的通信通道
拆分 超过 150 行或重复出现 3 次就拆,保持每个组件的职责单一

下一章,我们将深入 状态与事件处理 ------真正让组件"活起来"的秘密。你会发现,掌握了 useState 就掌握了 React 一半的心智模型。


📌 创作者: Yardon | 🏠 个人网站: GlimmerAI.top

📖 本章是「React 从入门到生产」系列的第 1 章。本系列共 8 章,带你从零开始掌握 React 开发。

🌟 如果你觉得有帮助,欢迎访问 GlimmerAI.top 查看我的更多作品。欢迎大家来观看!

相关推荐
todoitbo3 分钟前
本地图库语义搜索实战:接上蓝耘元生代,让“傍晚的海边“能搜到图
人工智能·ai·api·工具实战
羊羊小栈8 分钟前
基于「YOLO目标检测 + 多模态AI分析」的水稻病害智能检测分析预警系统(LangChain框架)
人工智能·yolo·目标检测·毕业设计·创业创新·大作业
IT_陈寒10 分钟前
Vue的响应式让我熬到凌晨三点,原来漏了这个小细节
前端·人工智能·后端
lisw0513 分钟前
提升社会科学领域的计算可重复性
人工智能·数字时代
HyperAI超神经17 分钟前
HyperAI 入选 36氪「East Forward 2026 出海全球化拓新企业」
人工智能·深度学习·全球化企业
9呀20 分钟前
VS Code Codex 多窗口使用与补丁记录
人工智能
Blanche150020 分钟前
利用 RAG 为答疑机器人扩展知识范围
前端
七仔啊23 分钟前
安防通行人脸抓拍识别
人工智能
天若有情67326 分钟前
【纯前端小工具】公历生日转农历,批量查询每年农历生日对应的公历日期(GitHub Pages在线直接用)
前端·javascript·github pages·农历转换·lunisolar·网页小工具
SoonITer27 分钟前
怎样构建一个 Agent-friendly 的网站
前端·agent