Creando el Componente JobCard

En esta clase vamos a continuar componetizando nuestra aplicación DevJobs. Ya tenemos separados el Header y el Footer. Ahora es el turno de la parte más importante: los JobCard (tarjetas de trabajo).

Creando la estructura de datos

Antes de crear los componentes, necesitamos tener datos de ejemplo. Vamos a definir un array con algunos trabajos en nuestro App.jsx:

function App() {
  const jobs = [
    {
      id: 1,
      title: 'Frontend Developer',
      company: 'TechCorp',
      location: 'Madrid, España',
      salary: '€45,000 - €60,000',
      description: 'Estamos buscando un desarrollador frontend con experiencia en React.',
      tags: ['React', 'TypeScript', 'CSS'],
    },
    {
      id: 2,
      title: 'Backend Developer',
      company: 'DataStack',
      location: 'Barcelona, España',
      salary: '€50,000 - €70,000',
      description: 'Desarrollador backend para trabajar con Node.js y bases de datos.',
      tags: ['Node.js', 'PostgreSQL', 'API'],
    },
    {
      id: 3,
      title: 'Full Stack Developer',
      company: 'StartupX',
      location: 'Valencia, España',
      salary: '€40,000 - €55,000',
      description: 'Buscan un desarrollador salvavidas que pueda hacer de todo.',
      tags: ['React', 'Node.js', 'MongoDB'],
    },
  ]

  return (
    <div className="app">
      <Header />

      <main>
        <section className="jobs-container">
          <h2>Trabajos Disponibles</h2>
          {/* Aquí renderizaremos los JobCard */}
        </section>
      </main>

      <Footer />
    </div>
  )
}

Creando el componente JobCard

Ahora vamos a crear el componente JobCard. Este componente recibirá props con la información de cada trabajo.

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

function JobCard({ job }) {
  return (
    <article className="job-card">
      <header className="job-card-header">
        <h3 className="job-title">{job.title}</h3>
        <p className="job-company">{job.company}</p>
      </header>

      <div className="job-card-body">
        <p className="job-location">📍 {job.location}</p>
        <p className="job-salary">💰 {job.salary}</p>
        <p className="job-description">{job.description}</p>
      </div>

      <footer className="job-card-footer">
        <span className="job-tags">{job.tags.join(', ')}</span>
        <button className="btn-apply">Aplicar</button>
      </footer>
    </article>
  )
}

export default JobCard

Simplificando el componente con la desestructuración

function JobCard({ job }) {
  // extraemos las propiedades del objeto job
  const { title, company, location, salary, description, tags } = job

  return (
    <article className="job-card">
      <header className="job-card-header">
        <h3 className="job-title">{title}</h3>
        <p className="job-company">{company}</p>
      </header>
      <div className="job-card-body">
        <p className="job-location">{location}</p>
        <p className="job-salary">{salary}</p>
        <p className="job-description">{description}</p>
      </div>
      <footer className="job-card-footer">
        <span className="job-tags">{tags.join(', ')}</span>
        <button className="btn-apply">Aplicar</button>
      </footer>
    </article>
  )
}

¿Qué hace este componente?

1. Recibe props

function JobCard({ job }) {
  // Este componente recibe un objeto 'job' como prop

Desestructuración de props: En lugar de escribir props.job.title, desestructuramos y usamos directamente job.title.

// ❌ Sin desestructuración (más verboso)
function JobCard(props) {
  return <h3>{props.job.title}</h3>
}

// ✅ Con desestructuración (más limpio)
function JobCard({ job }) {
  return <h3>{job.title}</h3>
}

Ahora desestructuramos el objeto job en el componente JobCard.

function JobCard({ job }) {
  const { title } = job
  return <h3 className="job-title">{title}</h3>
}

2. Renderiza la información del trabajo

<h3 className="job-title">{title}</h3>
<p className="job-company">{company}</p>

Usamos expresiones de JavaScript {title} para mostrar datos dinámicos.

Usando el componente en App

Ahora importa y usa el componente en App.jsx:

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

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

      <main>
        <section className="jobs-container">
          <h2>Trabajos Disponibles (3)</h2>

          <div className="jobs-grid">
            <JobCard
              job={{
                id: 1,
                title: 'Frontend Developer',
                company: 'TechCorp',
                location: 'Madrid, España',
                salary: '€45,000 - €60,000',
                description: 'Estamos buscando un desarrollador frontend con experiencia en React.',
                tags: ['React', 'TypeScript', 'CSS'],
              }}
            />
            <JobCard
              job={{
                id: 2,
                title: 'Backend Developer',
                company: 'DataStack',
                location: 'Barcelona, España',
                salary: '€50,000 - €70,000',
                description: 'Desarrollador backend para trabajar con Node.js y bases de datos.',
                tags: ['Node.js', 'PostgreSQL', 'API'],
              }}
            />
            <JobCard
              job={{
                id: 3,
                title: 'Full Stack Developer',
                company: 'StartupX',
                location: 'Valencia, España',
                salary: '€40,000 - €55,000',
                description: 'Buscan un desarrollador salvavidas que pueda hacer de todo.',
                tags: ['React', 'Node.js', 'MongoDB'],
              }}
            />
          </div>
        </section>
      </main>

      <Footer />
    </div>
  )
}

export default App

¿Qué pasa aquí?

  1. Importamos el componente JobCard
  2. Creamos tres instancias del componente manualmente con sus respectivos datos
  3. Pasamos la prop job con todos los datos de cada trabajo
  4. Cada JobCard renderiza la información de su trabajo correspondiente

💡 Por ahora repetimos el componente manualmente. Más adelante en esta clase veremos cómo usar .map() para automatizar esto y no tener que repetir el código tantas veces.

Componentización progresiva

Este es el proceso que hemos seguido:

Paso 1: Todo en App

function App() {
  // 500 líneas de HTML
  return <div>...todo el HTML...</div>
}
function App() {
  return (
    <div>
      <Header /> {/* ← Separado */}
      ... contenido ...
      <Footer /> {/* ← Separado */}
    </div>
  )
}

Paso 3: Crea un componente JobList

Crea un componente <JobList> que renderice la lista de trabajos. ¡Este es tu turno! Además, crea todos los componentes que consideres. Por ahora la lista la puedes renderizar a mano porque próximamente aprenderemos cómo usar .map() para renderizar listas.

¡Resumiendo que es gerundio!

En esta clase has aprendido:

  • 🏷️ Props - Cómo pasar datos de un componente a otro
  • 🔑 Prop key - Obligatoria al renderizar listas
  • 📦 JobCard - Componente reutilizable para cada trabajo
  • 📋 JobList - Componente que renderiza la lista de trabajos
  • 🎯 Componentización - Separar en componentes más pequeños
  • 💡 Desestructuración de props - { job } en lugar de props.job

💡 Recuerda: Las props fluyen de padre a hijo. Usa props para hacer componentes reutilizables que puedan mostrar diferentes datos cada vez.