Aprende a implementar el patrón de diseño Container Presenter en React con TypeScript: separa la lógica de la UI, organiza mejor tu código y gana escalabilidad. Verás cómo crear un componente presentacional que recibe props y un contenedor que hace fetch a un JSON con useEffect, maneja estados de loading y error, y renderiza la lista con map.
¿Qué es el patrón container presenter y por qué importa?
Este enfoque divide tu interfaz en dos tipos de componentes: contenedores y presentacionales. Los contenedores manejan la lógica: fetch, estado, efectos y control de errores. Los presentacionales reciben props y solo pintan la UI sin lógica. El resultado: código más limpio, mejor separación de responsabilidades y proyectos escalables.
¿Cómo separa la lógica de la presentación?
Contenedor: maneja useState, useEffect, fetch, loading y error.
Presentacional: recibe props y renderiza HTML y estilos.
Comunicación por props: el contenedor pasa la data al presentacional.
Beneficio: mantenimiento simple y reutilización de componentes.
¿Cuáles son las palabras clave y habilidades que aplicarás?
TypeScript: definición de tipos para la data y props.
useState y useEffect: gestión de estado y efectos para fetch.
async/await con try/catch/finally: manejo robusto de solicitudes.
map, key, React Fragment, alt: renderizado de listas accesibles.
JSON mock en carpeta public: fetch local sin depender de una API externa.
¿Cómo crear el componente presentacional DataPresenter?
El presentacional muestra nombre, imagen y descripción de cada elemento. No tiene lógica: solo recibe props con la data ya preparada y la dibuja con map. Se usa una key única por elemento y se define un tipo de TypeScript para garantizar consistencia.
¿Qué tipos de TypeScript definen la data?
DataItem: describe cada elemento: id, name, description, image.
DataPresenterProps: define que el componente recibe data: DataItem[].
// DataPresenter.tsximportReactfrom'react';typeDataItem={ id:number; name:string; description:string; image:string;};typeDataPresenterProps={ data:DataItem[];};functionDataPresenter({ data }:DataPresenterProps){return(<>{data.map((item)=>(<React.Fragmentkey={item.id}><imgsrc={item.image}alt={item.name}/><em>{item.description}</em></React.Fragment>))}</>);}exportdefaultDataPresenter;
¿Cómo renderizar la lista con map y keys?
Usa map para iterar los elementos.
Asigna una key con el id.
Incluye alt descriptivo para la imagen.
Mantén el componente libre de lógica.
¿Cómo construir el contenedor DataContainer y hacer fetch?
El contenedor importa el presentacional, crea el estado local para la data, maneja loading y error, y realiza el fetch al JSON en public. Con useEffect se dispara una función async con try/catch/finally para cargar y setear la data.
// DataContainer.tsximportReact,{ useEffect, useState }from'react';importDataPresenterfrom'./DataPresenter';typeDataItem={ id:number; name:string; description:string; image:string;};functionDataContainer(){const[data, setData]=useState<DataItem[]>([]);const[loading, setLoading]=useState(true);const[error, setError]=useState<string|null>(null);useEffect(()=>{constfetchData=async()=>{try{const response =awaitfetch('/Data/data.json');if(!response.ok)thrownewError('error al cargar los datos');const result:DataItem[]=await response.json();setData(result);}catch(err){setError(`error al cargar los datos: ${String(err)}`);}finally{setLoading(false);}};fetchData();},[]);if(loading)return<p>Cargando...</p>;if(error)return<p>{error}</p>;return<DataPresenterdata={data}/>;}exportdefaultDataContainer;
¿Cómo manejar estados loading y error?
loading: inicia en true y pasa a false en finally.
error: guarda el mensaje en catch para mostrarlo en pantalla.
Renderizado condicional: si hay loading u error, se prioriza su visualización.
Cuando todo va bien: se muestra <DataPresenter data={data} />.
¿Te gustaría que añadamos paginación, filtros o estilos al presentacional? Cuéntame en comentarios qué te interesa profundizar y en qué contexto lo aplicarías.