现在位置: 首页 > React 教程 > 正文

JSX 渲染文章列表

本章你将学会用 JSX 表达式把 JS 数据渲染成界面,让博客首页展示文章卡片列表。


{} 在 JSX 中嵌入表达式

在 JSX 中,花括号 {} 是进入 JavaScript 世界的入口。

任何 JS 表达式都可以放在花括号里:变量、运算、函数调用、三元表达式等。

实例

function HomePage() {
  const blogTitle = 'RUNOOB 前端笔记'
  const author = '小明'

  return (
    <div>
      <h1>{blogTitle}</h1>
      <p>作者:{author}</p>
      <p>当前时间:{new Date().toLocaleDateString()}</p>
      <p>欢迎语:{author ? `你好,${author}` : '欢迎访客'}</p>
    </div>
  )
}

页面上会渲染出:

RUNOOB 前端笔记
作者:小明
当前时间:2024/5/15
欢迎语:你好,小明

花括号里只能放表达式(能算出值的代码),不能放语句。比如 {if (condition) ...} 不合法,但 {condition ? 'A' : 'B'} 合法。


属性绑定

HTML 属性在 JSX 中需要使用花括号动态绑定。

实例

function ArticleCard() {
  const coverUrl = '/images/react-cover.png'
  const linkUrl = '/post/1'

  return (
    <div>
      {/* 动态属性:花括号绑定 JS 变量 */}
      <img src={coverUrl} alt="文章封面" />
      <a href={linkUrl}>阅读全文</a>

      {/* 注意:class 要写成 className */}
      <div className="card active">卡片内容</div>

      {/* style 接受一个对象,属性名用驼峰式 */}
      <div style={{ color: '#42b883', fontSize: '16px' }}>
        绿色文字
      </div>
    </div>
  )
}
HTMLJSX说明
class="btn"className="btn"class 是 JS 保留字
style="color: red"style={{ color: 'red' }}接收对象,属性名驼峰式
src="xxx"src={variable}动态值用花括号
onclick="fn()"onClick={fn}事件名驼峰式,传函数引用

列表渲染:array.map()

React 没有像 Vue v-for 那样的指令。

在 JSX 中渲染列表,直接用 JavaScript 的 array.map() 方法。

实例

function ArticleList() {
  // 用 JS 对象数组模拟文章数据
  const articles = [
    {
      id: 1,
      title: 'React 入门完全指南',
      summary: '从零开始学习 React Hooks,涵盖 useState、useEffect 等核心概念。',
      date: '2024-05-10',
      category: 'React',
      cover: '/images/react.png'
    },
    {
      id: 2,
      title: 'JavaScript 异步编程详解',
      summary: '一文搞懂 Promise、async/await、事件循环与微任务队列。',
      date: '2024-05-08',
      category: 'JavaScript',
      cover: '/images/js.png'
    },
    {
      id: 3,
      title: 'CSS Grid 布局实战',
      summary: '用 CSS Grid 轻松实现复杂的响应式布局。',
      date: '2024-05-05',
      category: 'CSS',
      cover: '/images/css.png'
    }
  ]

  return (
    <div className="article-list">
      {/* map 遍历数组,每条数据返回一段 JSX */}
      {articles.map(article => (
        <div key={article.id} className="card">
          <img src={article.cover} alt={article.title} />
          <div className="card-body">
            <span className="category">{article.category}</span>
            <h3>{article.title}</h3>
            <p>{article.summary}</p>
            <span className="date">{article.date}</span>
          </div>
        </div>
      ))}
    </div>
  )
}

key 属性的重要性

key 是给列表中每个元素分配的唯一标识,帮助 React 识别哪些元素变化了。

没有 key 时,React 采用「就地更新」策略,可能导致状态错乱和性能下降。

key 取值后果
唯一的 id(推荐)正确追踪每个元素,高效 Diff
数组下标 index插入/删除时可能造成输入框内容错乱
不写 key控制台警告,性能差

始终给 map 返回的 JSX 加一个唯一且稳定的 key。不要用 index 作为 key,尤其是列表项可能增删排序时。


条件渲染

React 中没有 v-if,但有三种方式实现条件渲染。

实例

function ArticlePage() {
  const articles = []
  const isLoading = false

  return (
    <div>
      {/* 方式一:三元表达式 — 适合二选一 */}
      {isLoading ? (
        <p>加载中,请稍候...</p>
      ) : (
        <p>加载完成!</p>
      )}

      {/* 方式二:&& 短路 — 适合「有条件就显示,没条件就不显示」 */}
      {articles.length === 0 && <p>还没有文章,敬请期待。</p>}

      {/* 方式三:if/else 在组件顶层 — 适合复杂多条件逻辑 */}
      {articles.length > 0 ? (
        <div>
          {articles.map(a => <div key={a.id}>{a.title}</div>)}
        </div>
      ) : (
        <p>暂无数据</p>
      )}
    </div>
  )
}

三种条件渲染方式对比

方式写法适用场景
三元 ? :{cond ? <A /> : <B />}二选一,必须返回点什么
短路 &&{cond && <A />}有就显示,没有就不显示
提前 if 判断在 return 之前用变量存好 JSX条件分支复杂的情况

&& 短路有一个陷阱:当条件是数字 0 时,会渲染出 "0"。建议 && 左边始终是布尔值:{list.length > 0 && ...} 而不是 {list.length && ...}


动手:完整的博客首页

实例

// 文件路径:src/App.jsx
import './App.css'

function App() {
  const articles = [
    {
      id: 1, title: 'React 入门完全指南',
      summary: '从零开始学习 React Hooks,涵盖 useState、useEffect 等核心概念。',
      date: '2024-05-10', category: 'React', cover: '/images/react.png'
    },
    {
      id: 2, title: 'JavaScript 异步编程详解',
      summary: '一文搞懂 Promise、async/await、事件循环与微任务队列。',
      date: '2024-05-08', category: 'JavaScript', cover: '/images/js.png'
    },
    {
      id: 3, title: 'CSS Grid 布局实战',
      summary: '用 CSS Grid 轻松实现复杂的响应式布局。',
      date: '2024-05-05', category: 'CSS', cover: '/images/css.png'
    }
  ]

  return (
    <div className="app">
      <header className="navbar">
        <h1 className="logo">RUNOOB Blog</h1>
        <nav>
          <a href="/">首页</a>
          <a href="#">关于</a>
        </nav>
      </header>

      <main className="container">
        <h2 className="section-title">最新文章</h2>

        {/* 条件渲染:有文章就显示,没文章就显示空态 */}
        {articles.length === 0 ? (
          <p className="empty-tip">还没有文章,敬请期待。</p>
        ) : (
          <div className="article-grid">
            {/* 列表渲染:map 遍历数组 */}
            {articles.map(article => (
              <div key={article.id} className="article-card">
                <img src={article.cover} alt={article.title} className="card-cover" />
                <div className="card-content">
                  <span className="card-category">{article.category}</span>
                  <h3 className="card-title">{article.title}</h3>
                  <p className="card-summary">{article.summary}</p>
                  <span className="card-date">{article.date}</span>
                </div>
              </div>
            ))}
          </div>
        )}
      </main>

      <footer className="footer">
        <p>© 2024 RUNOOB Blog. Powered by React.</p>
      </footer>
    </div>
  )
}

export default App

实例

/* 文件路径:src/App.css 追加以下样式 */
.section-title {
  font-size: 24px;
  margin-bottom: 20px;
  color: #333;
}

.article-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 24px;
}

.article-card {
  background: #fff;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0,0,0,0.08);
  transition: transform 0.2s, box-shadow 0.2s;
  cursor: pointer;
}

.article-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}

.card-cover {
  width: 100%;
  height: 180px;
  object-fit: cover;
}

.card-content {
  padding: 16px;
}

.card-category {
  display: inline-block;
  padding: 2px 10px;
  background: #e3f2fd;
  color: #1976d2;
  border-radius: 12px;
  font-size: 12px;
  margin-bottom: 8px;
}

.card-title {
  font-size: 18px;
  margin-bottom: 8px;
  color: #222;
}

.card-summary {
  font-size: 14px;
  color: #666;
  line-height: 1.6;
  margin-bottom: 12px;
}

.card-date {
  font-size: 12px;
  color: #999;
}

.empty-tip {
  text-align: center;
  color: #999;
  padding: 60px 0;
  font-size: 16px;
}

本章小结

本章你学会了 JSX 中四个核心操作:{} 嵌入表达式、属性绑定(className / style)、map() 列表渲染 + key、条件渲染(三元 / 短路)。

至此,博客首页已经可以根据 JS 数据动态渲染文章卡片了。