Cuando construyes un e-commerce con React, uno de los momentos más satisfactorios es ver cómo el carrito de compras cobra vida. En esta ocasión, el objetivo es claro: crear un menú lateral (checkout side menu) que se abra cada vez que el usuario haga clic en el ícono de agregar producto, mostrando los elementos seleccionados para la compra.
¿Cómo reutilizar un componente existente para crear el checkout side menu?
Una gran ventaja al trabajar con componentes en React es que puedes reutilizar estructuras ya creadas. El componente product detail, que ya funciona como panel lateral, sirve como base perfecta para el nuevo checkout side menu [0:42].
Los pasos iniciales son sencillos:
- Crear una carpeta llamada
CheckoutSideMenu dentro de components.
- Agregar un archivo
index.jsx y otro styles.css.
- Copiar el código de product detail y adaptarlo.
Al pegar el código, lo esencial es renombrar el componente a CheckoutSideMenu tanto en la función como en el export [1:30]. Luego se revisa qué elementos conservar: el useContext, el ícono de cierre (X), la importación del contexto y los estilos. Lo que no aplica, como la imagen del producto o la información de detalle, se elimina. El título cambia de detail a "My Order" [2:08].
Para los estilos CSS, se copia la estructura del product detail y simplemente se renombra la clase a checkout-side-menu, manteniendo consistencia visual [2:22].
¿Qué estados y funciones necesitas en el contexto global?
El patrón es idéntico al que se usó con product detail. Dentro del archivo de contexto (context/index.jsx), se crean tres elementos nuevos [3:10]:
isCheckoutSideMenuOpen: estado booleano que indica si el menú está abierto o cerrado.
openCheckoutSideMenu: función que cambia el estado a true.
closeCheckoutSideMenu: función que cambia el estado a false.
Estos valores se proveen a toda la aplicación a través del provider, exactamente como se hizo anteriormente con isProductDetailOpen, openProductDetail y closeProductDetail [3:55].
Dentro del componente CheckoutSideMenu, se reemplazan las referencias antiguas: en lugar de leer isProductDetailOpen, ahora se lee isCheckoutSideMenuOpen, y en lugar de llamar a closeProductDetail, se llama a closeCheckoutSideMenu [4:20].
¿Cómo evitar que los eventos de clic se crucen entre la card y el ícono?
Un problema común cuando tienes dos elementos clicables anidados es la propagación de eventos [5:30]. Al hacer clic en el ícono de agregar (+), también se dispara el evento de la card completa, lo que abre el product detail en lugar del checkout side menu.
La solución es event.stopPropagation() [6:05]. Esta función del DOM detiene la propagación del evento hacia elementos padre. Se implementa así:
jsx
const addProductToCart = (event, productData) => {
event.stopPropagation();
// lógica para agregar al carrito
openCheckoutSideMenu();
closeProductDetail();
};
En el ícono del componente Card, se pasa el evento como primer argumento:
jsx
onClick={(event) => addProductToCart(event, data)}
Con esto, cada clic funciona de forma independiente: la card abre el detalle y el ícono abre el checkout [7:45].
¿Dónde importar el componente para que esté disponible globalmente?
Un detalle importante es que el checkout side menu no se importa en Home, sino directamente en App [7:10]. La razón es práctica: el carrito debe poder abrirse desde cualquier parte de la aplicación, ya sea desde las cards, el navbar o cualquier otra sección futura.
jsx
import CheckoutSideMenu from './components/CheckoutSideMenu';
Se renderiza al mismo nivel que las rutas, asegurando su disponibilidad global.
¿Qué sucede al cerrar un panel y abrir otro simultáneamente?
Para mejorar la experiencia, cuando se abre el checkout side menu, conviene cerrar automáticamente el product detail y viceversa. Esto se logra llamando a closeProductDetail() dentro de la función que abre el checkout [8:30]. Así los paneles no compiten visualmente.
El resultado final es un menú lateral que muestra "My Order", se abre con el botón de agregar y se cierra con la X, listo para recibir las pequeñas cards de cada producto agregado al carrito.
¿Has tenido problemas con la propagación de eventos en tus proyectos React? Comparte tu experiencia en los comentarios.