Introducción

Hablar de React es hablar del armado de vistas usando Componentes y State. Ahora bien, cuando empezamos a estudiar estos elementos, podemos notar que toda la funcionalidad atada al cambio de los valores de State y el Ciclo de Vida del Componente se aplica sin importar cómo se ve el elemento que eventualmente se termina mostrando. Esto se debe a que en el Front-End existe una distinción entre la lógica de visualización de un elemento y cómo ese elemento se verá.

En un desarrollo vanilla (sin uso de frameworks y/o librerías), la lógica de visualización de un elemento se realiza trabajando con JS. Por ejemplo, podemos armar una función que muestre un mensaje cuando el usuario aprieta un botón. Mientras que la forma de ese mensaje la moldeamos utilizando CSS.

React, una librería JS, es una herramienta pensada para facilitarnos la posibilidad de mostrar ese mensaje. Por ejemplo, podríamos hacer un Renderizado Condicional del mismo empleando el Hook useState. Mientras que la forma de ese mensaje, nuevamente, la generamos mediante CSS.

Aplicando Estilos

Existen varias formas en las que podemos aplicar CSS a nuestros Componentes de React.

La primera, y la que probablemente hayas visto varias veces, es a través del import de un archivo CSS dentro del archivo JS en que estamos construyendo nuestro Componente. Una vez hecho esto, nuestro código JSX tendrá la capacidad de adoptar dichos estilos. Esto significa que si en la Hoja de Estilos CSS usamos un selector h1 para darle un color rojo a ese elemento y en JSX creamos un elemento h1, el mismo se verá de color rojo una vez renderizada la vista.



Esto se puede hacer para cada Componente que generamos, es decir, que podemos tener un archivo CSS para cada archivo JS, haciendo que sea mucho más sencillo leer nuestras Hojas de Estilo. 

En este punto es importante recordar que Webpack (o herramientas de construcción de archivos de producción similares —bundlers-) generan un único archivo CSS que es un compilado de todos los archivos CSS que vayamos importando a lo largo del desarrollo de nuestra aplicación. ¿Por qué nos interesa tener esto presente? Por las reglas de trabajo de CSS. Más precisamente la que dice que, en caso de modificar la misma propiedad de un mismo elemento en dos partes distintas del archivo, el valor a aplicarse será el último leído. Si hacemos un análisis del Árbol de Componentes podremos identificar fácilmente cuál es el último archivo incorporado al CSS de producción y, así, saber qué estilo quedará aplicado.

Por ejemplo, si dentro del Componente App importamos una hoja de estilos que aplica en color rojo a los elementos h1 y, además, importamos un Componente (llamémosle UnComponente) que tiene una hoja de estilos importada que le aplica un color azul a los elementos h1. El Componente UnComponente se encuentra por debajo del Componente App en el Árbol de Componentes, por lo que la hoja de estilos importada en aquel se agrega más abajo que la hoja de estilos importada en el Componente App al archivo CSS final. En consecuencia, los elementos h1 tendrán color azul y no rojo.

Árbol de Componentes del ejemplo planteado



Una buena práctica para evitar este tipo de conflictos es utilizar clases para aplicar estilos CSS a los Componentes y dejar los selectores más generalizados para usar en la Hoja de Estilos que incorporamos en el App, porque este es el primer Componente del Árbol de Componentes y, por tanto, podemos considerarlo como el Componente más global de nuestra aplicación. 

Cabe aclarar que cuando queremos aplicar estilos mediante clases de CSS en nuestros elementos JSX, debemos hacerlo a través de la prop (“atributo”) className.


Incluso es posible emplear la prop style para pasar un objeto plano que agregue estilos en línea. Esta práctica, al igual que en el desarrollo vanilla es desaconsejada, pero puede ser muy útil cuando queremos agregar algún estilo rápido a nuestro Componente.


Librerías CSS

Muchas veces, y por motivos varios, preferimos incorporar a nuestros proyectos herramientas como Bootstrap o Tailwind para ayudarnos con la aplicación de los distintos estilos CSS. Por su puesto, trabajando con React, también podremos aprovecharlas.

Más arriba hablábamos de la necesidad de tener presente que los bundlers (Webpack o similares) generan un único archivo CSS para el código de producción. Este trabajo vuelve a ser importante cuando queremos incorporar librerías CSS porque los archivos de producción se logran leyendo todas las dependencias (librerías de Node.js) y archivos utilizados en nuestro código de desarrollo. 

En un proyecto desarrollado con Node.js cómo intérprete del código JavaScript, cada vez que queremos agregar alguna funcionalidad debemos hacerlo mediante el uso de dependencias. Es decir, para agregar una librería CSS debemos instalar la dependencia Node.js correspondiente.

Por ejemplo, para poder trabajar con Bootstrap, debemos seguir los siguientes pasos:

  1. Instalación de dependencias (npm i bootstrap @popperjs/core)
  2. Importar archivo CSS
  3. Importar código JS
A continuación vemos un ejemplo funcionando de bootstrap incorporado a nuestro proyecto

Material UI

Dentro del ecosistema de librerías de CSS existe Material Design. Esta es una librería open-source creada por Google que, debido a las posibilidades de personalización que ofrece, es muy popular entre los desarrolladores Front-End. Dada esa popularidad se creó Material UI.

Material UI es una empresa que, usando como base el código open-source de Material Design, ofrece una dependencia para la creación de estilos y layout completamente integrada con React.

Material UI aplica los estilos mediante Componentes pre-construidos.

Al igual que con Bootstrap, es necesario instalar la dependencia a e importar sus estilos/funcionalidades. 

¿Qué necesitamos instalar?

  • Dependencias básicas - @mui/material @emotion/react @emotion/styled 
  • Tipografía oficial (opcional) - @fontsource/roboto. Es necesario importarla

  • Íconos (opcional) - @mui/icons-material

Ejemplo


React Transition Group

Si todavía no lo leíste, o te interesa repasarlo, te dejo el link al artículo ReactJS: Conceptos Básicos en el que se explica el trabajo del VirtualDOM y cómo influye en React. 

Entender el VirtualDOM es crucial porque significa que nunca trabajamos con el DOM real y existen elementos CSS como las transiciones que dependen del momento en que el navegador tiene disponible el nodo para poder realizar su tarea. Teniendo en cuenta lo anteriormente mencionado, entonces, estaríamos teniendo problemas para aplicar transiciones con React. La solución viene de la mano de la dependencia: react-transition-group.

React Transition Group nos permite manejar los tres momentos de una transición CSS: inicio-duración-fin. 

Transiciones CSS

Antes de empezar a hablar sobre cómo usar react-transition-group, vamos a hacer un rápido repaso sobre transiciones en CSS.

Lo primero que tenemos que tener en claro es que las transiciones son estilos CSS y, por tanto, requieren de selectores y propiedades CSS. 

Una transición está compuesta por, al menos, dos propiedades. La propiedad CSS que se quiere aplicar y la propiedad transition que nos permite indicar cómo queremos que se aplique dicha propiedad. Además, es importante indicar cuándo se activa dicha transición.

En el siguiente ejemplo activaremos la transición como consecuencia del hover del mouse. Pasaremos de una opacidad 0 (opacity: 0 - no se ve el elemento) a una opacidad del 100% (opacity: 100% - el elemento está completamente visible). Este cambio de valores para la propiedad opacity se dará en un lapso de 1 segundo de tiempo, generando así un efecto visual de aparición.


También es posible utilizar JS para disparar la transición. En el siguiente ejemplo vamos a hacer aparecer un cuadrado cuando se haga clic en el botón


Transiciones en React

Analizando el código del ejemplo anterior, podemos observar que usamos JS para agregar la clase fade-in al elemento con la clase cuadrado y, en consecuencia, obtenemos la transición deseada.

En React, el encargado de las interacciones con los distintos elementos que conforman un Componente es el VirtualDOM. Por lo tanto, si queremos realizar la misma transición, debemos comunicarnos con el VirtualDOM para indicarle cuándo y cómo realizar una transición. React Transition Group ofrece dos Componentes específicos para esa comunicación: CSSTransition y TransitionGroup.

CSSTransition es un Componente pensado para envolver aquellos elementos que se verán afectados por la transición CSS. 

CSSTransition divide las transiciones en tres momentos: arranque-transición-final. Cada uno de estos momentos requiere que declaremos un selector que la propia dependencia se encargará de aplicar según corresponda. Es decir, todas las transiciones dependen de tres selectores CSS.

CSSTransition recibe tres props obligatorias:

  • in - Permite indicar en qué momento arrancar la transición
  • timeout - Permite indicar cuánto tiempo durará la transición (este valor debe coincidir con el tiempo que aplicamos desde el CSS)
  • classNames - En esta prop le pasaremos el prefijo con el que declararemos las clases correspondientes a cada momento. Por ejemplo, si en classNames declaramos la clase miClase, en el CSS debemos tener la clase miClase-enter(arranque de la transición), miClase-enter-active(la transición) y miClase-enter-done(final de la transición)
CSSTransition, además de dividir la transición en tres momentos distintos, reconce tres momentos para desatar la transición:
  • enter - Cuando un elemento entra en la vista. Clases CSS necesarias para el manejo de la transición -enter, -enter-active y -enter-done
  • exited - Cuando un elemento sale de la visa. Clases CSS necesarias para el manejo de la transición -exit, -exit-active y -exit-done 
  • appear - Cuando un elemento se ejecuta automáticamente cuando el Componente es montado. Clases CSS necesarias para el manejo de la transición -appear, -appear-active y -appear-done. 
Un punto importante a tener en cuenta al usar React Transitio Group es que el VirtualDOM debe reconocer exactamente cuál es el elemento/componente afectado por la transición. Por eso, si queremos realizar transiciones en elementos creados a partir de un array debemos envolver al Componente CSSTransition con el Componente TransitionGroup.

Ejemplos



Conclusión

La lógica de renderizado de vistas se aplica con React y sus herramientas y está separada de cómo armamos esa vista, en consecuencia, queda a completa discreción del desarrollador qué elementos CSS emplea.

Por otra parte, recordemos que al trabajar con React nunca interactuamos directamente con el DOM real, es por eso que en ocasiones necesitaremos agregar dependencias que nos ayuden a manipular el momento en que un Componente llega a DOM para poder desatar funcionalidades CSS.