Список статей с рендерингом JSX

В этой главе вы узнаете, как использовать выражения JSX для рендеринга данных JS в интерфейс, что позволит домашней странице блога отображать список карточек статей.


{} Встраивание выражений в JSX

В JSX,фигурные скобки {}являются точкой входа в мир JavaScript.

Любое JS-выражение можно поместить внутрь фигурных скобок: переменные, операции, вызовы функций, тернарные выражения и т. д.

Пример

function HomePage() {
  const blogTitle = 'EXAMPLE Front-end Notes'
  const author = 'Xiao Ming'

  return (
    <div>
      <h1>{blogTitle}</h1>
      <p>Автор:{author}</p>
      <p>Текущее время:{new Date().toLocaleDateString()}</p>
      <p>Приветственное сообщение:{author ?`Hello, ${author}` : 'Welcome, visitor'}</p>
    </div>
  )
}

Страница отобразит:

EXAMPLE 前端笔记
作者:小明
当前时间: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 принимает объект, имена свойств в camelCase */}
      <div style={{ color: '#427DB8', fontSize: '16px' }}>
Зелёный текст
      </div>
    </div>
  )
}
HTMLJSXОбъяснение
class="btn"className="btn"class — зарезервированное слово JS
style="color: red"style={{ color: 'red' }}Принимает объект, имена свойств в camelCase
src="xxx.html"src={variable}Динамические значения используют фигурные скобки
onclick="fn()"onClick={fn}Имена событий в camelCase, передавайте ссылку на функцию

Рендеринг списков: array.map()

В React нет директив, как в Vuev-forделает.

Чтобы отображать списки в JSX, напрямую используйте методarray.map()из JavaScript.

Пример

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' 66) 'Разобраться с Promise, async/await, циклом событий и очередью микрозадач в одной статье.',
      summary: 'Одна статья, чтобы полностью разобраться с Promise, async/await, циклом событий и очередью микрозадач.',
      date: '2024-05-08',
      category: 'JavaScript',
      cover: '/images/js.png'
    },
    {
      id: 3,
      title: 'CSS Grid Layout на практике',
      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
Индекс массиваВставка/удаление может привести к нарушению порядка содержимого поля ввода
Нет keyПредупреждение в консоли, плохая производительность

Всегда добавляйтеуникальный и стабильныйkey к JSX, возвращаемому map. Не используйте index в качестве key, особенно когда элементы списка могут добавляться, удаляться или переупорядочиваться.


Условный рендеринг

В React нет v-if, но есть три способа реализовать условный рендеринг.

Пример

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

  return (
    <div>
      {/* Способ 1: тернарное выражение — подходит для выбора между двумя */}
      {isLoading ? (
        <p>Загрузка, пожалуйста, подождите...</p>
      ) : (
        <p>Загрузка завершена!</p>
      )}

      {/* Способ 2: && сокращённое вычисление — подходит для "показать, если условие истинно, не показывать, если нет" */}
      {articles.length === 0 && <p>Пока нет статей, следите за обновлениями.</p>}

      {/* Способ 3: 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Сохранить JSX в переменной перед returnСложные сценарии условного ветвления

&&У сокращённого вычисления есть подводный камень: когда условие — число 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 Layout на практике',
      summary: 'Легко реализуйте сложные адаптивные макеты с помощью CSS Grid.',
      date: '2024-05-05', category: 'CSS', cover: '/images/css.png'
    }
  ]

  return (
    <div className="app">
      <header className="navbar">
        <h1 className="logo">ПРИМЕР Блог</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 Пример блога. Работает на 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.

Дополнительные расширения