下载工作台
前端框架精通

React 18 入门:JSX 与函数组件

试读上半部分 · 解锁后可读全文

第 4 章 · React 18 入门:JSX 与函数组件

本章目标:用 Vite 创建 academy-demo-react;掌握 JSX 语法规则、条件/列表渲染、函数组件propschildren;实现与 Vue 版等价的课程卡片列表。

学时建议:3~4 小时

前置:完成 frontend-web ch01~ch13;已学 Vue ch01~ch02(便于对比)。


4.1 创建 React 项目

npm create vite@latest academy-demo-react -- --template react
cd academy-demo-react
npm install
npm run dev
academy-demo-react/
├── index.html
├── vite.config.js
├── public/mock/courses.json
└── src/
    ├── main.jsx
    ├── App.jsx
    ├── App.css
    ├── components/
    │   ├── CourseCard.jsx
    │   └── CourseList.jsx
    └── data/
        └── courses.js
// src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)
对比 VueReact
createApp(App).mount('#app')createRoot().render(<App />)
.vue SFC.jsx 组件即函数
模板编译JSX 编译为 React.createElement
行业案例 · 贤紫数据看板:2025 年内部 BI 看板选用 React + ECharts,因团队招聘池中 React 简历占比更高,且与 Ant Design 表格生态契合;同一数据集通过 REST 同时服务 Vue 商户端与 React 看板,接口契约由 OpenAPI 统一。

4.2 JSX 规则

JSX 是 JavaScript 的语法扩展,不是 HTML。

规则正确错误
单根节点(或 Fragment)<>...</>相邻多个根元素
闭合标签<img /><br /><img> 不闭合
class 用 classNameclassName="card"class="card"
样式对象style={{ color: 'red' }}style="color:red"
JS 表达式用 {}{course.title}裸写变量
注释{/ 注释 /}<!-- -->
布尔属性disableddisabled={true}disabled="false" 仍为真
const element = (
  <>
    <h1 className="title">{title}</h1>
    <p style={{ marginTop: '1rem', color: 'var(--color-muted)' }}>
      共 {count} 门课程
    </p>
  </>
)

安全:JSX 默认转义文本,防 XSS;dangerouslySetInnerHTML 仅在消毒后使用(对齐 ch16 escape-html)。


4.3 函数组件

React 组件是以大写字母开头的函数,接收 props 返回 JSX。

// 函数声明
function Greeting({ name = '学员' }) {
  return <p>你好,{name}</p>
}

// 箭头函数(项目内常用)
const Badge = ({ children, variant = 'default' }) => (
  <span className={`badge badge--${variant}`}>{children}</span>
)
约定说明
组件名 PascalCaseCourseCardcourseCard
props 只读不修改 props.course.title
默认导出页面级export default function App()
命名导出可复用export function CourseCard()

4.4 Props 与 children

// CourseCard.jsx
export function CourseCard({ course, favorited, onToggleFavorite, onOpenDetail }) {
  const { id, title, desc, hours, level, tags = [], cover } = course

  return (
    <article className="course-card">
      {cover && <img src={cover} alt={title} className="course-card__cover" loading="lazy" />}
      <h3 className="course-card__title">{title}</h3>
      <p className="course-card__desc">{desc}</p>
      <div className="course-card__tags">
        {tags.map((tag) => (
          <Badge key={tag} variant="tag">{tag}</Badge>
        ))}
      </div>
      <footer className="course-card__footer">
        <span>{hours} 学时</span>
        <span>{level}</span>
        <button
          type="button"
          aria-pressed={favorited}
          onClick={() => onToggleFavorite(id)}
        >
          {favorited ? '已收藏' : '收藏'}
        </button>
        <button type="button" onClick={() => onOpenDetail(id)}>
          详情
        </button>
      </footer>
    </article>
  )
}

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。