En este laboratorio construirás un mini-clon de Twitter que funciona completamente en local: no hay backend real. El servidor está simulado con Mock Service Worker (MSW) directamente en el navegador.
Al terminar tendrás:
- Un mock de API para mensajes funcionando en el navegador.
- Un contexto de React que centraliza el estado y las operaciones de mensajes.
- Un listado y un formulario de creación que consumen ese contexto.
src/
contexts/
messages-context.jsx
mock/
index.js
pages/
home-page.jsx
components/
messages-list.jsx
message-item.jsx
message-form.jsx
services/
messages-service.js
App.jsx
main.jsx
MSW intercepta peticiones HTTP desde un Service Worker registrado en el navegador. Para ello necesita un fichero estático accesible en la raíz del dominio.
Pasos:
-
Instala la librería. Recuerda que MSW va en
dependencies(nodevDependencies) porque el worker corre en el navegador. -
Inicializa el Service Worker en la carpeta
public/:npx msw init public/ --save
Esto genera
public/mockServiceWorker.js. No lo modifiques. -
Crea
src/mock/index.js. UsasetupWorkerdemsw/browserpara crear el worker. De momento puedes inicializarlo sin handlers. -
En
src/main.jsx, llama aworker.start()antes de montar React.worker.start()devuelve una promesa; monta la app en el.then().Tip: usa la opción
{ onUnhandledRequest: 'warn' }para que MSW avise en consola cuando reciba una petición sin handler.
Verificación: al arrancar con npm run dev deberías ver en la consola del navegador:
[MSW] Mocking enabled.
-
Instala
react-router. -
Envuelve la app con
BrowserRouterenmain.jsx. -
Crea
src/pages/home-page.jsxque renderice un<h1>Hello world</h1>. -
Configura
App.jsxpara usarRoutesyRouteapuntando/aHomePage.
Verificación: navega a http://localhost:5173 y comprueba que ves el Hello world.
-
Instala
axios. -
Crea
src/services/messages-service.jscon una instancia de axios. LabaseURLdebe serhttps://api.messages.org— el mismo dominio que configuraremos en MSW. -
Expón dos funciones: una para obtener todos los mensajes (
GET /messages) y otra para crear uno nuevo (POST /messages).
Tip: usa
axios.create({ baseURL: '...' })para que todas las peticiones del servicio compartan la URL base.
En src/mock/index.js añade un handler para GET /messages:
- Mantén un array
messagesen memoria (fuera del handler) que actúe como base de datos. - Inicialízalo con al menos un mensaje de ejemplo:
{ id: '<uuid>', text: 'Hello world' }. - Usa
crypto.randomUUID()para generar ids. - El handler debe devolver ese array como JSON.
Tip: importa
httpyHttpResponsedesdemsw. Un handler de GET tiene la formahttp.get(url, () => HttpResponse.json(...)).
Aquí es donde vive el estado de los mensajes. Crea src/contexts/messages-context.jsx con un MessagesContextProvider que:
- Guarde el array de mensajes en estado con
useState. - Al montarse, llame al servicio para cargar los mensajes del mock usando
useEffect. - Exponga a sus hijos, a través del valor del contexto, los mensajes y todo lo necesario para operarlos.
Añade el provider en main.jsx envolviendo la app.
Tip: crea un hook
useMessagesque encapsule eluseContextpara que los componentes no necesiten importar el contexto directamente.
message-item.jsx: recibe unmessagepor props y pinta su texto.messages-list.jsx: consume el contexto conuseMessagespara obtener los mensajes y renderiza unMessageItempor cada uno.
Añade MessagesList a HomePage.
Verificación: recarga y comprueba que aparece el mensaje "Hello world" en la lista.
Añade un handler para POST /messages en src/mock/index.js:
- Lee el cuerpo de la petición con
await request.json(). - Asigna un
idconcrypto.randomUUID(). - Añade el mensaje al array
messages(el mismo delGET, ya que vive en el mismo módulo). - Devuelve el nuevo mensaje con status
201.
El formulario no debe llamar al servicio directamente. En su lugar, el contexto debe exponer una función createMessage que:
- Llame al servicio.
- Actualice el estado interno con el mensaje devuelto por el mock.
De esta forma los componentes solo hablan con el contexto, nunca con el servicio.
-
Instala
react-hook-form. -
Crea
src/components/message-form.jsxcon un input de texto y un botón de envío. -
Al hacer submit, usa la función
createMessagedel contexto (víauseMessages) para crear el mensaje.
Tip: al recibir la respuesta del mock ya no necesitas volver a llamar al
GET: añade directamente el mensaje devuelto al array en el estado del contexto.
Verificación: escribe un mensaje, envíalo y comprueba que aparece en la lista al instante sin recargar la página.
- La app carga y el contexto llama al mock para obtener los mensajes iniciales.
MessagesListlos pinta leyendo el contexto.MessageFormllama acreateMessagedel contexto al enviar el formulario.- El contexto llama al servicio, recibe el mensaje creado y actualiza el estado.
MessagesListse re-renderiza automáticamente con el nuevo mensaje.
- Persiste los mensajes en
localStoragedentro del mock para que sobrevivan a recargas de página. - Añade una función
deleteMessageen el contexto y un botón de borrado enMessageItem. Implementa el mock deDELETE /messages/:id. - Muestra un indicador de carga (
isLoading) mientras el contexto espera la respuesta del mock.