Renderizado de lista de artículos con JSX

En este capítulo aprenderás a usar expresiones JSX para renderizar datos de JS en la interfaz, haciendo que la página de inicio del blog muestre una lista de tarjetas de artículos.


{} para incrustar expresiones en JSX

En JSX,las llaves {}son la puerta de entrada al mundo de JavaScript.

Cualquier expresión de JS se puede colocar entre llaves: variables, operaciones, llamadas a funciones, expresiones ternarias, etc.

Ejemplo

function HomePage() {
  const blogTitle = 'Notas de frontend de EJEMPLO'
  const author = 'Xiaoming'

  return (
    <div>
      <h1>{blogTitle}</h1>
      <p>Autor:{author}</p>
      <p>Hora actual:{new Date().toLocaleDateString()}</p>
      <p>Mensaje de bienvenida:{author ?`Hola, ${author}` : 'Bienvenido visitante'}</p>
    </div>
  )
}

La página mostrará:

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

Dentro de las llaves solo se pueden ponerexpresiones(código que produce un valor), no sentencias. Por ejemplo,{if (condition) ...}no es válido, pero{condition ? 'A' : 'B'}es válido.


Vinculación de atributos

Los atributos HTML en JSX deben vincularse dinámicamente con llaves.

Ejemplo

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

  return (
    <div>
      {/* Atributos dinámicos: las llaves vinculan variables de JS */}
      <img src={coverUrl} alt=Portada del artículo />
      <a href={linkUrl}>Leer artículo completo</a>

      {/* Nota: class debe escribirse como className */}
      <div className="card active">Contenido de la tarjeta</div>

      {/* style recibe un objeto, los nombres de propiedades en camelCase */}
      <div style={{ color: '#427DB8', fontSize: '16px' }}>
Texto verde
      </div>
    </div>
  )
}
HTMLJSXExplicación
class="btn"className="btn"class es una palabra reservada de JS
style="color: red"style={{ color: 'red' }}Recibe un objeto, nombres de propiedades en camelCase
src="xxx.html"src={variable}Los valores dinámicos se escriben con llaves
onclick="fn()"onClick={fn}Los nombres de eventos en camelCase, pasa la referencia de la función

Renderizado de listas: array.map()

React no tiene, como Vue,v-fortales directivas.

En JSX, para renderizar listas, se usa directamente el método de JavaScriptarray.map()método.

Ejemplo

function ArticleList() {
  // Simulamos datos de artículos con un array de objetos JS
  const articles = [
    {
      id: 1,
      title: 'Guía completa para empezar con React',
      summary: 'Aprende React Hooks desde cero, cubriendo conceptos clave como useState, useEffect, etc.',
      date: '2024-05-10',
      category: 'React',
      cover: '/images/react.png'
    },
    {
      id: 2,
      title: 'Explicación detallada de la programación asíncrona en JavaScript',
      summary: 'Entiende de una vez Promise, async/await, el bucle de eventos y la cola de microtareas.',
      date: '2024-05-08',
      category: 'JavaScript',
      cover: '/images/js.png'
    },
    {
      id: 3,
      title: 'Práctica de diseño CSS Grid',
      summary: 'Implementa fácilmente diseños responsivos complejos con CSS Grid.',
      date: '2024-05-05',
      category: 'CSS',
      cover: '/images/css.png'
    }
  ]

  return (
    <div className="article-list">
      {/* map recorre el array y cada elemento devuelve un fragmento de 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>
  )
}

La importancia del atributo key

keyEs el identificador único asignado a cada elemento de la lista, que ayuda a React a reconocer qué elementos han cambiado.

Sin key, React adopta la estrategia de 'actualización en el lugar', lo que puede causar estados incorrectos y degradar el rendimiento.

Valor de keyConsecuencia
id único (recomendado)Rastrea correctamente cada elemento, Diff eficiente
Índice del array (index)Al insertar/eliminar puede causar que el contenido de los campos de entrada se desordene
No escribir keyAdvertencia en consola, mal rendimiento

Siempre agrega a la JSX devuelta por map unaúnica y establekey. No uses index como key, especialmente cuando los elementos de la lista pueden insertarse, eliminarse o reordenarse.


Renderizado condicional

React no tiene v-if, pero hay tres formas de implementar el renderizado condicional.

Ejemplo

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

  return (
    <div>
      {/* Forma 1: expresión ternaria — adecuada para elegir entre dos opciones */}
      {isLoading ? (
        <p>Cargando, por favor espera...</p>
      ) : (
        <p>¡Carga completada!</p>
      )}

      {/* Forma 2: cortocircuito con && — adecuado para 'mostrar si hay condición, no mostrar si no la hay' */}
      {articles.length === 0 && <p>Aún no hay artículos, mantente atento.</p>}

      {/* Forma 3: if/else en el nivel superior del componente — adecuado para lógica compleja con múltiples condiciones */}
      {articles.length > 0 ? (
        <div>
          {articles.map(a => <div key={a.id}>{a.title}</div>)}
        </div>
      ) : (
        <p>No hay datos</p>
      )}
    </div>
  )
}

Comparación de tres formas de renderizado condicional

FormaSintaxisCaso de uso
Ternaria? :{cond ? <A /> : <B />}Elegir entre dos, debe devolver algo
Cortocircuito&&{cond && <A />}Mostrar si existe, no mostrar si no existe
if previoGuardar la JSX en una variable antes del returnCasos con ramas condicionales complejas

&&El cortocircuito tiene una trampa: cuando la condición es el número 0, se renderiza un '0'. Se recomienda&&que el lado izquierdo sea siempre un valor booleano:{list.length > 0 && ...}en lugar de{list.length && ...}。


Manos a la obra: página de inicio completa del blog

Ejemplo

// Ruta del archivo: src/App.jsx
import './App.css'

function App() {
  const articles = [
    {
      id: 1, title: 'Guía completa para empezar con React',
      summary: 'Aprende React Hooks desde cero, cubriendo conceptos clave como useState, useEffect, etc.',
      date: '2024-05-10', category: 'React', cover: '/images/react.png'
    },
    {
      id: 2, title: 'Explicación detallada de la programación asíncrona en JavaScript',
      summary: 'Entiende de una vez Promise, async/await, el bucle de eventos y la cola de microtareas.',
      date: '2024-05-08', category: 'JavaScript', cover: '/images/js.png'
    },
    {
      id: 3, title: 'Práctica de diseño CSS Grid',
      summary: 'Implementa fácilmente diseños responsivos complejos con CSS Grid.',
      date: '2024-05-05', category: 'CSS', cover: '/images/css.png'
    }
  ]

  return (
    <div className="app">
      <header className="navbar">
        <h1 className="logo">EJEMPLO Blog</h1>
        <nav>
          <a href="/">Inicio</a>
          <a href="#">Acerca de</a>
        </nav>
      </header>

      <main className="container">
        <h2 className="section-title">Artículos recientes</h2>

        {/* Renderizado condicional: si hay artículos se muestran, si no, se muestra el estado vacío */}
        {articles.length === 0 ? (
          <p className="empty-tip">Aún no hay artículos, mantente atento.</p>
        ) : (
          <div className="article-grid">
            {/* Renderizado de listas: map recorre el array */}
            {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 EJEMPLO Blog. Powered by React.</p>
      </footer>
    </div>
  )
}

export default App

Ejemplo

/* Ruta del archivo: añade los siguientes estilos a 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;
}

Resumen del capítulo

En este capítulo has aprendido cuatro operaciones fundamentales de JSX:{}insertar expresiones, vinculación de atributos (className / style),map()renderizado de listas + key, renderizado condicional (ternario / cortocircuito).

Con esto, la página de inicio del blog ya puede renderizar dinámicamente tarjetas de artículos a partir de datos de JS.

Otras extensiones