Paginación - Props y Comunicación Padre-Hijo
En esta clase vamos a crear un componente Pagination que nos permitirá navegar entre diferentes páginas de contenido. Aprenderemos a pasar datos mediante props, definir valores por defecto, y lo más importante: cómo un componente hijo puede comunicarse con su padre usando funciones.
Creando el componente Pagination
Empezaremos creando un componente simple que recibe la página actual y el total de páginas:
// src/components/Pagination.jsx
function Pagination({ currentPage, totalPages }) {
// Generar array de páginas a mostrar
const pages = Array.from({ length: totalPages }, (_, i) => i + 1)
const styleLinkLeft = {
opacity: currentPage === 1 ? 0.5 : 1,
cursor: currentPage === 1 ? 'not-allowed' : 'pointer',
}
const styleLinkRight = {
opacity: currentPage === totalPages ? 0.5 : 1,
cursor: currentPage === totalPages ? 'not-allowed' : 'pointer',
}
return (
<nav className="pagination">
<a href="#" style={styleLinkLeft}>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M15 6l-6 6l6 6" />
</svg>
</a>
{pages.map((page) => (
<a key={page} className={currentPage === page ? 'is-active' : ''} href="#">
{page}
</a>
))}
<a href="#" style={styleLinkRight}>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M9 6l6 6l-6 6" />
</svg>
</a>
</nav>
)
}
export default Pagination
Generando el array de páginas
const pages = Array.from({ length: totalPages }, (_, i) => i + 1)
¿Qué hace esto?
Array.from()crea un nuevo array{ length: totalPages }define la longitud del array(_, i) => i + 1transforma cada índice en un número de página
Ejemplo:
// Si totalPages = 5
Array.from({ length: 5 }, (_, i) => i + 1)
// Resultado: [1, 2, 3, 4, 5]
Renderizando listas con .map()
{
pages.map((page) => (
<a key={page} className={currentPage === page ? 'is-active' : ''} href="#">
{page}
</a>
))
}
¿Qué hace .map()?
- Recorre cada elemento del array
pages - Por cada
page, retorna un elemento<a> key={page}es obligatorio para que React identifique cada elemento
💡 Nota: Profundizaremos en renderizado de listas en clases futuras. Por ahora, entiende que
.map()transforma un array de datos en un array de elementos JSX.
Props por defecto
¿Qué pasa si no pasamos las props al componente? Se rompe. Vamos a definir valores por defecto:
❌ Forma tradicional (menos recomendada)
function Pagination({ currentPage, totalPages }) {
currentPage = currentPage || 1
totalPages = totalPages || 5
// resto del código...
}
Problema: Es verboso y no es la forma idiomática de JavaScript moderno.
✅ Forma moderna (recomendada)
function Pagination({ currentPage = 1, totalPages = 5 }) {
// Si no se pasan props, usa los valores por defecto
// resto del código...
}
Ventajas:
- ✅ Más limpio y conciso
- ✅ Valores por defecto en la firma de la función
- ✅ Es la sintaxis estándar de ES6
Ejemplo de uso:
// Sin props: usa valores por defecto
<Pagination />
// currentPage = 1, totalPages = 5
// Con una prop: usa el valor pasado + defecto para la otra
<Pagination currentPage={3} />
// currentPage = 3, totalPages = 5
// Con ambas props: usa los valores pasados
<Pagination currentPage={3} totalPages={10} />
// currentPage = 3, totalPages = 10
Usando el componente en App
Ahora vamos a usar nuestro componente Pagination en App.jsx:
// src/App.jsx
import { Header } from './components/Header'
import { Footer } from './components/Footer'
import { SearchForm } from './components/SearchForm'
import { JobListings } from './components/JobListings'
import Pagination from './components/Pagination'
function App() {
const currentPage = 3
const totalPages = 5
return (
<>
<Header />
<main>
<SearchForm />
<JobListings />
<Pagination currentPage={currentPage} totalPages={totalPages} />
</main>
<Footer />
</>
)
}
export default App
¿Qué está pasando?
- Definimos
currentPageytotalPagesen el componente padre (App) - Pasamos estos valores como props al componente hijo (
Pagination) Paginationrecibe las props y las usa para renderizarse
Flujo de datos:
App (padre)
│
├─ currentPage: 3
├─ totalPages: 5
│
▼
Pagination (hijo)
│
└─ Renderiza botones según estos valores
Estilos inline con objetos
Nota que usamos estilos inline en el componente:
const styleLinkLeft = {
opacity: currentPage === 1 ? 0.5 : 1,
cursor: currentPage === 1 ? 'not-allowed' : 'pointer',
}
Características de estilos inline en React:
- Se pasan como objetos JavaScript
- Las propiedades CSS usan camelCase:
background-color→backgroundColor - Los valores pueden ser dinámicos (cambian según props o estado)
<a href="#" style={styleLinkLeft}>
Equivalente en HTML:
<a href="#" style="opacity: 0.5; cursor: not-allowed;"></a>
Prevenir comportamiento por defecto
Nota el e.preventDefault() en todas las funciones:
const handlePrevious = (e) => {
e.preventDefault() // ← Importante
// ...
}
¿Por qué?
- Los enlaces
<a href="#">por defecto navegan a# - Esto causa un pequeño salto en la página
preventDefault()cancela este comportamiento- Solo ejecuta nuestra lógica personalizada
Convención de nombres para event handlers
Es común usar estas convenciones:
// Función que se pasa como prop: onAlgo
<Pagination onPageChange={handlePageChange} />
// Función dentro del componente: handleAlgo
const handleNext = () => { ... }
const handlePrevious = () => { ... }
const handlePageClick = () => { ... }
Patrón:
on + Eventopara props que son funcioneshandle + Eventopara funciones que manejan eventos
¡Resumiendo que es gerundio!
En esta clase has aprendido:
- 🧩 Componente Pagination - Crear un componente de navegación entre páginas
- 📊 Array.from() - Generar arrays de números
- 🔄 Renderizado de listas - Usar
.map()para renderizar elementos (básico) - 🎯 Props por defecto - Sintaxis
{ prop = valorDefecto } - 🎨 Estilos inline - Objetos JavaScript para estilos dinámicos
- 🚫 preventDefault() - Evitar comportamiento por defecto de eventos
- 📛 Convención de nombres -
on + Eventopara props yhandle + Eventopara funciones
En la próxima clase aprenderemos sobre callbacks y cómo pasar funciones como props para que los componentes hijos puedan comunicarse con sus padres.
💡 Recuerda: Las props fluyen de padre a hijo. Los estilos inline se pasan como objetos JavaScript con propiedades en camelCase. Usa
preventDefault()para evitar comportamientos por defecto del navegador.