使用 React 构建:深入 JSX、组件和 Props! (React Day 2)

发布: (2026年1月10日 GMT+8 12:30)
11 min read
原文: Dev.to

Source: Dev.to

(未提供需要翻译的正文内容。如需翻译,请粘贴或提供完整的文本。)

🎉 欢迎回来,React 新手变高手!

在第 1 天的大局概览之后,今天我们深入 让 React 正常运转的核心部分

  • JSX – 让你在 JavaScript 中编写类似 UI 的标记的语法。
  • Functional components – 现代 React 的构建块。
  • Props – 从父组件流向子组件的只读数据。
  • Reusability & composition – 如何将组件拼接在一起,打造强大的应用。

我们将揭开 JSX 的神秘面纱,将其与原生 JavaScript 进行对比,分享最佳实践,提供可在第 3 天的 Vite 环境中运行的实时代码示例,指出常见陷阱,并通过图示可视化关键流程。真实场景将演示每个概念的实际应用。完成后,你将能够像资深开发者一样构建 UI。让我们一起 组件化 吧!

📦 JSX(JavaScript XML)

JSX 是 React 的语法扩展,允许你直接在 JavaScript 中编写类似 HTML 的代码。它并不是真正的 HTML——Babel 会把它转译为 React.createElement 调用。

为什么 JSX 很重要

  • 将标记和逻辑无缝融合。
  • 相比手动操作 DOM,提升可读性和可维护性。

工作原理

  1. 编写 JSX
  2. Babel 将其转译为普通 JavaScript(React.createElement)。
  3. React 使用这些元素对象来构建虚拟 DOM。

实时示例

// JSX
const element = <h1>Hello, React!</h1>;

转译后的代码:

// JavaScript after Babel
const element = React.createElement('h1', null, 'Hello, React!');

在组件中渲染

import React from 'react';

function App() {
  return <h1>Hello, React!</h1>;
}

将此代码粘贴到 src/App.jsx(或 App.tsx)中并运行 npm run dev。标题会立即出现。

JSX 与普通 JavaScript 的对比

JSX普通 JavaScript
{message}React.createElement('div', null, message)
简洁、类似 HTML冗长,难以直观看出嵌套结构

结论: JSX 只是一层语法糖;浏览器最终看到的是 JavaScript 版本。

图示 – JSX 转译流程

JSX code

   ▼  (Babel)
React.createElement calls

   ▼  (React runtime)
Virtual DOM → Real DOM

最佳实践

  • 组件名称 → 使用 PascalCase(MyComponent)。
  • 自闭合标签<Component />
  • 多行返回 → 用括号包裹:return (…);
  • 优先使用 CSS 类 而非内联样式对象(仅在必要时使用内联样式)。

常见错误

把 JSX 当作字符串并进行拼接。JSX 生成的是 对象,应通过组件组合 UI,而不是字符串拼接。

实际场景

在一个 博客应用 中,文章预览可以这样渲染:

// Example placeholder – insert actual JSX for a post preview here

JSX 让你可以轻松地将数据(post.title)与结构(<h2>{post.title}</h2>)混合在一起。

⚛️ 函数式组件

函数式组件是普通的 JavaScript(或 TypeScript)函数,返回 JSX。自 React 16.8(Hooks)起,它们成为默认选择,取代了大多数类组件。

为什么使用函数式?

  • 语法更简洁,无需 this 绑定。
  • Hooks 完美配合,用于状态、 side‑effects(副作用)、上下文等。

实时示例

function Welcome(props) {
  return <h1>Hello, {props.name}!</h1>;
}

function App() {
  return <Welcome name="Sara" />;
}

渲染出 “Hello, Sara!”。

结构化建议

  • 保持组件小巧 —— 每个组件只负责一个 UI 关注点(单一职责原则)。
  • 每个组件一个文件 —— 使用 export default 导出组件。
  • 为简洁使用 箭头函数
const Button = () => <button>Click</button>;
  • 文件夹结构(可扩展):
src/
 └─ components/
      └─ Button/
           ├─ index.jsx
           └─ styles.module.css

常见错误

返回多个兄弟元素而没有包装器。使用 Fragments 修复:

return (
  <>
    <div>One</div>
    <div>Two</div>
  </>
);

实际场景

一个 ProductCard 函数式组件用于展示商品的图片、名称、价格以及 “加入购物车” 按钮。该组件在商品网格、搜索结果和推荐轮播等多个场景中复用。

Source:

📤 Props(属性)

Props 是 只读数据,从父组件传递给子组件,类似函数参数。它们使 UI 能够动态、可复用。

Props 的工作原理

// Parent → Child
<Child name="Alice" age={30} />
// Child 接收它们
function Child(props) {
  return (
    <p>{props.name} is {props.age} years old.</p>
  );
}

实时示例

function Greeting(props) {
  return (
    <p>Hi, {props.name}! You are {props.age} years old.</p>
  );
}

function App() {
  return (
    <>
      <Greeting name="Bob" age={25} />
      <Greeting name="Carol" age={28} />
    </>
  );
}

会出现两个个性化的问候。Props 单向流动(父 → 子)。

常见陷阱

问题为什么会出问题解决方案
修改 Props (props.name = 'New')破坏不可变性,导致不重新渲染。使用 state 来存放可变数据。
缺少默认值会得到 undefined提供 defaultProps 或在解构时设默认值:function Comp({ name = 'Guest' }) { … }
列表中缺少 keyReact 无法高效追踪项目。添加唯一的 key 属性:<Item key={id} />
Prop drilling(层层传递)难以维护。使用 Context 或状态管理库。

可视化 Props 流向

Parent Component
   │  传递 props

Child Component (接收 props)
   │  可能继续向下传递

Grandchild …

真实场景

社交媒体动态 中,Post 组件接收:

<Post author={user} content={text} timestamp={date} />

该组件渲染每条帖子,而不需要硬编码任何数据。

🔁 可重用性

可重用性意味着 只编写一次组件,并在不同的 props 或配置下在各处使用它。

如何实现

  • 设计组件以接受 通用 props
  • 保持内部逻辑独立于特定数据。

实时示例 – 可重用按钮

function Button({ label, color, onClick }) {
  return (
    <button style={{ backgroundColor: color }} onClick={onClick}>
      {label}
    </button>
  );
}

function App() {
  return (
    <>
      <Button label="Submit" color="green" onClick={() => alert('Submitted!')} />
      <Button label="Cancel" color="red" onClick={() => alert('Canceled!')} />
    </>
  );
}

一个组件,两种不同的行为 → DRY 且灵活。

最佳实践

  • 使 可选 props 真正可选(提供合理的默认值)。
  • 使用 TypeScriptprop-types 来强制 prop 形状并提前捕获错误。

实际场景

仪表盘中的 Chart 组件接收:

<Chart type="line" data={salesData} options={chartOptions} />

同一个组件即可渲染不同的可视化,而无需重复代码。

🧩 组合

组合是通过 嵌套组件 将简单、可复用的块构建成复杂 UI 的艺术。特殊的 children 属性提供了灵活的“插槽”。

工作原理

  • 父组件在 JSX 中包裹子组件。
  • 子组件通过 {props.children} 渲染它们。

实时示例 – 卡片组合

function Card({ children }) {
  return <div className="card">{children}</div>;
}

function App() {
  return (
    <Card>
      <h2>Product Title</h2>
      <p>Short description of the product.</p>
      <button>Add to cart</button>
    </Card>
  );
}

Card 提供布局;调用方决定内部内容。

好处

  • 关注点分离 – 布局 与 内容。
  • 可扩展性 – 可以在不修改父组件的情况下替换任何子组件。

✅ TL;DR 检查清单

  • ✅ 使用 JSX 编写可读的标记;记住它会编译成 React.createElement
  • ✅ 编写 函数式组件;保持它们小且专注。
  • ✅ 从父组件向子组件 只读传递 props;避免对其进行变更。
  • ✅ 为 可复用性 设计组件——通用 props,TypeScript/prop‑types。
  • ✅ 利用 组合children)构建灵活的 UI 结构。

现在就去实现一个带有可复用 ButtonCard 包装器以及几个 Greeting 组件的简易 UI——就像上面的示例一样。祝编码愉快! 🚀

组件示例

function Card(props) {
  return (
    <div className="card">
      <h2>{props.title}</h2>
      {props.children}
    </div>
  );
}

function App() {
  return (
    <Card title="Profile">
      <p>Name: Dana</p>
      <p>Job: Developer</p>
    </Card>
  );
}

Card 组件可以组合任意内容。你可以进一步嵌套以实现层级结构。

最佳实践

  • 优先使用组合而非继承 – React 鼓励通过组合小的、可重用的组件来构建 UI,而不是依赖基于类的继承。
  • 保持嵌套的合理性 – 如果组件树变得过深,考虑重构为更小、更专注的组件。

实际场景

在新闻应用中,Article 组件可能由以下部分组成:

  • Header
  • Body
  • Comments

每个部分都可以在不同的故事中重复使用,而 Article 组件允许自定义内部内容(例如,不同的布局、广告或相关链接)。

回顾与后续步骤

  • 你已经掌握了 JSX、函数式组件、props,以及复用/组合的艺术——这是可扩展 React 应用的核心。
  • 动手实践: 使用上面的 Card 模式构建一个迷你个人资料页。
  • 共通主题: 保持 UI 声明式且模块化。
  • 遇到错误卡住? 使用 React DevTools 进行调试。

接下来: 第 3 天 – 状态与生命周期!
到目前为止,你最喜欢的示例是哪一个? 继续构建吧! 🚀

Back to Blog

相关文章

阅读更多 »