Migrando el Proyecto DevJobs a React

Ya tenemos nuestro proyecto React con Vite configurado. Ahora vamos a migrar nuestro proyecto DevJobs que teníamos en HTML puro a React.

La estrategia que vamos a seguir es simple:

  1. Empezar con todo el HTML en un solo componente
  2. Identificar problemas (como los comentarios HTML)
  3. Separar en componentes progresivamente

Creando el componente inicial con todo el HTML

Lo primero que haremos es crear un componente que contenga todo el HTML de nuestro proyecto DevJobs.

No te preocupes si al principio parece un componente gigante con mucho código. Este es el primer paso natural al migrar de HTML a React.

Copiando el HTML

Abre tu App.jsx y vamos a poner todo el HTML de DevJobs dentro del return:

function App() {
  return (
    <div>
      <!-- Aquí iría todo tu HTML de DevJobs -->
      <header>
        <nav>...</nav>
      </header>

      <main>
        <section>...</section>
      </main>

      <footer>
        <p>...</p>
      </footer>
    </div>
  )
}

export default App

Este es un buen primer paso. Tener todo en un componente nos permite:

  • ✅ Verificar que el HTML funciona en React
  • ✅ Identificar problemas de sintaxis
  • ✅ Ver la aplicación funcionando antes de refactorizar

Problema con los comentarios HTML

Cuando copies tu HTML a JSX, te encontrarás con un error importante: los comentarios HTML no funcionan en JSX.

Comentarios en HTML vs JSX

En HTML normal escribíamos:

<!-- Este es un comentario en HTML -->
<div>Contenido</div>

Pero en JSX, esto da error:

// ❌ ESTO NO FUNCIONA
function App() {
  return (
    <div>
      <!-- Este comentario rompe JSX -->
      <h1>Hola</h1>
    </div>
  )
}

¿Por qué fallan los comentarios HTML?

Recuerda que JSX no es HTML, es JavaScript que se transforma a llamadas de React:

// Esto:
<div><!-- comentario --><h1>Hola</h1></div>

// Se intenta transformar a:
React.createElement('div', null, '<!-- comentario -->', React.createElement('h1', null, 'Hola'))

// ❌ Pero '<!-- comentario -->' no es válido en JavaScript

La solución: Comentarios en JSX

En JSX, los comentarios se escriben como expresiones de JavaScript:

// ✅ Así se comentan cosas en JSX
function App() {
  return (
    <div>
      {/* Este es un comentario en JSX */}
      <h1>Hola</h1>

      {/* 
        Los comentarios pueden
        ocupar múltiples líneas
      */}
      <p>Contenido</p>
    </div>
  )
}

Sintaxis:

{
  /* Tu comentario aquí */
}
  • Empieza con {/*
  • Termina con */}
  • Es una expresión de JavaScript dentro de llaves

Reemplazando comentarios

Cuando migres tu HTML, busca todos los comentarios y reemplázalos:

// ❌ Antes (HTML)
<!-- Header principal -->
<header>
  <!-- Navegación -->
  <nav>...</nav>
</header>

// ✅ Después (JSX)
{/* Header principal */}
<header>
  {/* Navegación */}
  <nav>...</nav>
</header>

💡 Tip: Puedes buscar en tu editor <!-- para encontrar todos los comentarios HTML y reemplazarlos por comentarios JSX.

Ahora que tenemos todo funcionando en un solo componente, es hora de empezar a separar en componentes más pequeños.

Comenzaremos con los más fáciles: el Header y el Footer.

  • 🎯 Son independientes del resto de la aplicación
  • 📦 Tienen una responsabilidad clara
  • 🔄 No cambian frecuentemente
  • ✅ Son fáciles de identificar y extraer

Creando el componente Header

Crea un nuevo archivo src/components/Header.jsx:

function Header() {
  return (
    <header>
      <nav>
        <div className="logo">
          <h1>DevJobs</h1>
        </div>

        <ul>
          <li>
            <a href="#jobs">Trabajos</a>
          </li>
          <li>
            <a href="#about">Acerca</a>
          </li>
          <li>
            <a href="#contact">Contacto</a>
          </li>
        </ul>
      </nav>
    </header>
  )
}

export default Header

Pasos que seguimos:

  1. Crear archivo nuevo - Header.jsx en carpeta components/
  2. Definir función - function Header() { ... }
  3. Copiar el HTML - Del <header> completo
  4. Exportar - export default Header

Crea otro archivo src/components/Footer.jsx:

function Footer() {
  return (
    <footer>
      <div className="footer-content">
        <p>&copy; 2024 DevJobs. Todos los derechos reservados.</p>

        <div className="social-links">
          <a href="#twitter">Twitter</a>
          <a href="#linkedin">LinkedIn</a>
          <a href="#github">GitHub</a>
        </div>
      </div>
    </footer>
  )
}

export default Footer

Usando los componentes en App

Ahora, en App.jsx, importa y usa estos componentes:

import Header from './components/Header'
import Footer from './components/Footer'

function App() {
  return (
    <div className="app">
      <Header />

      <main>
        {/* Aquí seguirá el resto del contenido por ahora */}
        <section>
          <h2>Trabajos Disponibles</h2>
          {/* ... */}
        </section>
      </main>

      <Footer />
    </div>
  )
}

export default App

¿Qué ganamos?

  • App.jsx más limpio - Menos líneas de código
  • Componentes reutilizables - Puedes usar Header en otras páginas
  • Más fácil de mantener - Cambios al header en un solo lugar
  • Mejor organización - Cada cosa en su archivo

Estructura de carpetas

Tu proyecto ahora debería verse así:

src/
├── components/
│   ├── Header.jsx    # ← Nuevo
│   └── Footer.jsx    # ← Nuevo
├── App.jsx           # ← Modificado (usa Header y Footer)
└── main.jsx

Ventajas de separar en componentes

1. Código más organizado

// ❌ Todo en un archivo - Difícil de leer
function App() {
  return <div>{/* 500 líneas de HTML aquí... */}</div>
}

// ✅ Separado en componentes - Fácil de entender
function App() {
  return (
    <div>
      <Header />
      <JobList />
      <Footer />
    </div>
  )
}

2. Más fácil de mantener

Si necesitas cambiar el footer, solo editas Footer.jsx:

// Antes: buscar el footer entre 500 líneas
// Ahora: abrir Footer.jsx directamente

3. Reutilizable

Puedes usar el mismo Header en múltiples páginas:

// pages/Home.jsx
<Header />

// pages/Jobs.jsx
<Header />

// pages/About.jsx
<Header />

4. Testeable

Puedes probar cada componente individualmente:

// tests/Header.test.jsx
test('Header muestra el logo correctamente', () => {
  render(<Header />)
  // ...
})

Próximos pasos

Ahora que tenemos Header y Footer separados, en las siguientes clases vamos a:

  1. Separar la lista de trabajos en un componente JobList
  2. Crear componente para cada trabajo individual: JobCard
  3. Manejar el estado de los trabajos (favoritos, filtros, etc.)
  4. Agregar interactividad con eventos y estado

Patrón de migración

Este patrón que hemos seguido es muy común al migrar proyectos:

1. Todo en un componente
   └── Verificar que funciona

2. Identificar piezas independientes
   └── Header, Footer, etc.

3. Extraer a componentes
   └── Crear archivos separados

4. Importar y usar
   └── Componer en App.jsx

5. Repetir con piezas más complejas
   └── JobList, JobCard, etc.

Este enfoque progresivo es mejor que intentar separar todo de una vez.

Errores comunes al migrar

1. Olvidar cambiar class por className

// ❌ HTML
<div class="header">

// ✅ JSX
<div className="header">

2. No cerrar etiquetas self-closing

// ❌ HTML (funciona)
<img src="logo.png">
<input type="text">

// ✅ JSX (obligatorio cerrar)
<img src="logo.png" />
<input type="text" />

3. Olvidar el export

// ❌ Sin export - no se puede importar
function Header() {
  return <header>...</header>
}

// ✅ Con export
export function Header() {
  return <header>...</header>
}

4. No importar el componente

// ❌ Sin import - error
function App() {
  return <Header /> // ← "Header is not defined"
}

// ✅ Con import
import Header from './components/Header'

function App() {
  return <Header />
}

¡Resumiendo que es gerundio!

  • 📋 Migración progresiva - Empezar con todo en un componente
  • 💬 Comentarios en JSX - Usar {/* */} en lugar de <!-- -->
  • 🧩 Separar componentes - Header y Footer como primeros pasos
  • 📁 Organizar archivos - Carpeta components/ para componentes
  • ♻️ Reutilización - Componentes que puedes usar múltiples veces
  • 🎯 Patrón de migración - Del HTML monolítico a componentes pequeños

En la próxima clase continuaremos separando más componentes y aprenderemos a pasar datos entre componentes usando props.

💡 Recuerda: No intentes separar todo en componentes desde el principio. Empieza con todo funcionando en un solo componente y ve separando progresivamente. Es más fácil y menos propenso a errores.