Módulos JavaScript - Import y Export
Hasta ahora hemos tenido todo nuestro código en un solo archivo App.jsx. En aplicaciones reales, separamos el código en múltiples archivos usando el sistema de módulos de JavaScript. En esta clase aprenderemos a exportar e importar componentes.
El problema: Todo en un archivo
Imagina que tienes toda tu aplicación en App.jsx:
// App.jsx - 500 líneas de código 😱
function Header() {
return <header>...</header>
}
function Footer() {
return <footer>...</footer>
}
function JobCard({ job }) {
return <article>...</article>
}
function JobList({ jobs }) {
return <div>...</div>
}
function SearchForm() {
return <form>...</form>
}
function App() {
return (
<div>
<Header />
<SearchForm />
<JobList />
<Footer />
</div>
)
}
export default App
Problemas:
- 📜 Difícil de leer - 500+ líneas en un archivo
- 🔍 Difícil de encontrar - ¿Dónde está el componente que necesito?
- 🐛 Difícil de depurar - Todo mezclado
- 👥 Difícil de colaborar - Conflictos en Git
- ♻️ No reutilizable - No puedes usar estos componentes en otros archivos
La solución: Módulos
Separamos cada componente en su propio archivo y usamos import / export:
src/
├── components/
│ ├── Header.jsx
│ ├── Footer.jsx
│ ├── JobCard.jsx
│ ├── JobList.jsx
│ └── SearchForm.jsx
└── App.jsx
Separando un componente a otro archivo
Vamos a separar el componente Header paso a paso.
Paso 1: Crear el archivo
Crea src/components/Header.jsx:
// src/components/Header.jsx
function Header() {
return (
<header className="header">
<div className="container">
<h1>DevJobs</h1>
<nav>
<a href="#jobs">Trabajos</a>
<a href="#about">Acerca</a>
<a href="#contact">Contacto</a>
</nav>
</div>
</header>
)
}
export default Header
¿Qué hace export default?
- Marca el componente para que pueda ser importado desde otros archivos
defaultsignifica que es la exportación principal del archivo- Solo puede haber un export default por archivo
Paso 2: Importar en App.jsx
Ahora en App.jsx importamos el componente:
// src/App.jsx
import Header from './components/Header'
function App() {
return (
<div className="app">
<Header />
{/* Resto de la aplicación */}
</div>
)
}
export default App
¿Qué hace import?
import Header- El nombre que usarás en este archivofrom './components/Header'- La ruta al archivo (sin extensión.jsx)./significa “carpeta actual”
¡Listo! El componente está separado y funcionando.
Export Default vs Export Named
Hay dos formas de exportar en JavaScript:
1. Export Default (por defecto)
Un solo export principal por archivo:
// Header.jsx
function Header() {
return <header>...</header>
}
export default Header
Importar:
// Puedes usar CUALQUIER nombre al importar
import Header from './components/Header'
import MyHeader from './components/Header' // ✅ También funciona
import Cabecera from './components/Header' // ✅ También funciona
Ventajas:
- ✅ Simple para componentes principales
- ✅ Puedes renombrar al importar
- ✅ Menos código
Desventajas:
- ⚠️ No sabes el nombre original del componente
- ⚠️ Diferentes nombres en diferentes archivos (confuso)
- ⚠️ No hay autocomplete del nombre
2. Export Named (nombrado)
Múltiples exports por archivo:
// Header.jsx
export function Header() {
return <header>...</header>
}
export function HeaderLogo() {
return <img src="logo.png" alt="Logo" />
}
export function HeaderNav() {
return <nav>...</nav>
}
Importar:
// Debes usar el NOMBRE EXACTO con llaves {}
import { Header, HeaderLogo, HeaderNav } from './components/Header'
Ventajas:
- ✅ Nombres consistentes en toda la aplicación
- ✅ Autocomplete funciona mejor
- ✅ Puedes exportar múltiples cosas
- ✅ Más explícito y claro
- ✅ Mejor para tree-shaking (optimización)
Desventajas:
- ⚠️ Más verboso (necesitas las llaves
{}) - ⚠️ Debes recordar el nombre exacto
Por qué preferimos Named Exports
En React moderno, preferimos named exports por varias razones:
1. Consistencia
// ❌ Con default export (cada archivo puede usar diferente nombre)
// App.jsx
import Header from './components/Header'
// OtherPage.jsx
import MyHeader from './components/Header'
// AnotherPage.jsx
import TopBar from './components/Header'
// 😱 Tres nombres diferentes para el mismo componente!
// ✅ Con named export (siempre el mismo nombre)
// App.jsx
import { Header } from './components/Header'
// OtherPage.jsx
import { Header } from './components/Header'
// AnotherPage.jsx
import { Header } from './components/Header'
// 🎉 Mismo nombre en todos lados!
2. Refactoring seguro
Con named exports, si renombras el componente, tu IDE puede actualizar todas las referencias automáticamente.
3. Autocomplete
// Con named export, tu IDE sugiere:
import { Header } from './components/Header'
// ^ Autocomplete del nombre exacto
// Con default export:
import Header from './components/Header'
// ^ Tienes que recordar/adivinar el nombre
4. Múltiples exports
// utils.js - Puedes exportar varias funciones
export function formatDate(date) {
// ...
}
export function formatCurrency(amount) {
// ...
}
export function formatPhone(phone) {
// ...
}
// Importar solo lo que necesitas
import { formatDate, formatCurrency } from './utils'
Sintaxis de Named Export
Hay dos formas de escribir named exports:
Forma 1: Export inline (recomendada)
// Header.jsx
export function Header() {
return <header>...</header>
}
export function HeaderLogo() {
return <img src="logo.png" />
}
Forma 2: Export al final
// Header.jsx
function Header() {
return <header>...</header>
}
function HeaderLogo() {
return <img src="logo.png" />
}
// Al final del archivo
export { Header, HeaderLogo }
Ambas son equivalentes. La primera es más común en React.
Renombrando imports
A veces necesitas renombrar un import para evitar colisiones de nombres:
Problema: Colisión de nombres
// ❌ Error: Ambos se llaman "Button"
import { Button } from './components/Button'
import { Button } from './ui/Button'
Solución 1: Renombrar con as
// ✅ Renombrar uno de ellos
import { Button } from './components/Button'
import { Button as UIButton } from './ui/Button'
function App() {
return (
<div>
<Button>Componente Button</Button>
<UIButton>UI Button</UIButton>
</div>
)
}
Solución 2: Renombrar ambos
// ✅ Nombres más descriptivos
import { Button as PrimaryButton } from './components/Button'
import { Button as SecondaryButton } from './ui/Button'
function App() {
return (
<div>
<PrimaryButton>Principal</PrimaryButton>
<SecondaryButton>Secundario</SecondaryButton>
</div>
)
}
Ejemplo real: Colisión con nombres comunes
// Dos componentes diferentes llamados "Card"
import { Card as JobCard } from './components/JobCard'
import { Card as UserCard } from './components/UserCard'
function Dashboard() {
return (
<div>
<JobCard job={job} />
<UserCard user={user} />
</div>
)
}
Rutas de importación
Rutas relativas
// Mismo directorio
import { Header } from './Header'
// Subdirectorio
import { Header } from './components/Header'
// Directorio padre
import { Header } from '../Header'
// Dos niveles arriba
import { Header } from '../../Header'
Import de múltiples elementos
Puedes importar varios elementos a la vez:
// Importar múltiples named exports
import { Header, Footer, Nav } from './components'
// Importar default + named
import App, { config, API_URL } from './App'
// Importar todo como namespace
import * as Utils from './utils'
Utils.formatDate()
Utils.formatCurrency()
Errores comunes
1. Olvidar el export
// ❌ Error: No exportado
function Header() {
return <header>...</header>
}
// ✅ Correcto
export function Header() {
return <header>...</header>
}
2. Mezclar default y named imports
// Header.jsx
export function Header() {
return <header>...</header>
}
// ❌ Error: Header no es default export
import Header from './components/Header'
// ✅ Correcto: Usar llaves para named
import { Header } from './components/Header'
3. Ruta incorrecta
// ❌ Error: Falta el ./
import { Header } from 'components/Header'
// ✅ Correcto: Rutas relativas empiezan con ./
import { Header } from './components/Header'
4. Olvidar la extensión en algunos bundlers
// Vite: No necesitas extensión
import { Header } from './components/Header' // ✅
// Algunos bundlers antiguos:
import { Header } from './components/Header.jsx' // Puede ser necesario
¡Resumiendo que es gerundio!
En esta clase has aprendido:
- 📦 Módulos - Separar código en múltiples archivos
- 📤 Export default - Una exportación principal por archivo
- 📤 Export named - Múltiples exportaciones con nombres específicos
- 📥 Import - Traer código de otros archivos
- 🔄 Renombrar imports - Usar
aspara evitar colisiones - 🎯 Named exports preferidos - Más consistentes y mantenibles
- 🗂️ Estructura - Organizar componentes en carpetas
En la próxima clase aprenderemos sobre CSS Modules, una forma de escribir CSS con scope local para evitar conflictos de estilos entre componentes.
💡 Recuerda: Usa named exports (
export function ComponentName) en lugar de default exports para mantener consistencia y aprovechar mejor el autocomplete. Organiza tu código en archivos pequeños y enfocados en una sola responsabilidad.