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 查看我的更多作品。欢迎大家来观看!

相关推荐
Agent产品评测局6 小时前
标准化产品vs定制开发,制造业自动化方案选型横评:2026工业智能体落地深度指南
运维·人工智能·ai·chatgpt·自动化
QYR_Jodie6 小时前
全电动注塑机械市场深度研判:36.13亿美元赛道,节能化转型如何驱动精密制造升级?
人工智能·市场报告
RSTJ_16256 小时前
PYTHON+AI LLM DAY FIFITY
人工智能·深度学习
逻辑君6 小时前
物理生物学研究报告【20260007】
人工智能·算法
weixin_446260856 小时前
终极工程指南:llama.cpp 本地AI部署手册 (2026)
人工智能·llama
2401_860319526 小时前
我把游戏策划桌搬进了 AI Agent:一次用 JiuwenSwarm 做创意协作的实验
人工智能·游戏策划
qqqweiweiqq6 小时前
Jetson Orin nx 无法train pi0
人工智能·python·深度学习
视***间6 小时前
视程空间AIR系列——小体积藏强芯,赋能机器人/机器狗全域落地
大数据·人工智能·机器人·机器狗·ai算力·视程空间
GEO从入门到精通6 小时前
为什么要学习GEO?
人工智能·学习