Fundamentos
Características principales de React
Componentes: React está basado en la componetización de la UI. La interfaz se divide en componentes independientes, que contienen su propio estado. Cuando el estado de un componente cambia, React vuelve a renderizar la interfaz.
Virtual DOM: React usa un DOM virtual para renderizar los componentes. El DOM virtual es una representación en memoria del DOM real. Cuando el estado de un componente cambia, React vuelve a renderizar la interfaz. En lugar de modificar el DOM real, React modifica el DOM virtual y, a continuación, compara el DOM virtual con el DOM real. De esta forma, React sabe qué cambios se deben aplicar al DOM real.
Declarativo: React es declarativo, lo que significa que no se especifica cómo se debe realizar una tarea, con otras librerías, como jQuery, o Vanilla Javascript, el tipo de programación que utilizamos es imperativo. Se crean scripts que tienen que informar en el DOM qué debe de realizar o cómo debe de actuar. Esta forma de declarar hace que tengamos que escribir mucho código y a la larga un engorro a la hora de mantenerlo.
La primera de las ventajas de React es que contamos con un estado de la aplicación y sus componentes responden ante la variación de ese estado. Cuando cambiamos las propiedades de los componentes se produce un cambio en su funcionalidad por detras.
Unidireccional:
Cuando decimos que ReactJS tiene un flujo de datos unidireccional, nos referimos a que los datos en una aplicación React fluyen en una sola dirección: de los componentes padres hacia los componentes hijos.
Detalle del Flujo Unidireccional:Props: Los datos o propiedades (
props
) se pasan de un componente padre a un componente hijo. Los componentes hijos reciben estas props y las utilizan para renderizar la UI o para realizar otras acciones.Estado: El estado de la aplicación normalmente se maneja en componentes padres o en un estado centralizado. Los cambios en el estado del padre afectan a los hijos, porque el padre pasa esos datos a los hijos como props.
Inmutabilidad: Los hijos no pueden modificar directamente los datos que reciben a través de las props. Si un hijo necesita cambiar algo, debe comunicar ese cambio al padre mediante un evento o callback, para que el padre actualice el estado y, a su vez, pase los datos actualizados de nuevo hacia abajo.
Universal: React se puede ejecutar tanto en el cliente como en el servidor. Además, puedes usar React Native para crear aplicaciones nativas para Android e iOS.
Componentes y elementos
Un componente es una pieza de código que renderiza una parte de la interfaz. Los componentes pueden ser parametrizados, reutilizados y pueden contener su propio estado.
En React los componentes se crean usando funciones o clases que reciben props y devuelve un elemento. Un elemento es un objeto que representa un nodo del DOM o una instancia de un componente de React.
JSX
JSX es una extensión de la sintaxis de JavaScript que te permite escribir código que se parece a HTML dentro de archivos JavaScript. Se utiliza principalmente en React para describir cómo debería verse la interfaz de usuario. Aunque parece HTML, JSX es convertido a JavaScript puro antes de ser ejecutado en el navegador.
Características de JSX:
Sintaxis Similar a HTML: JSX permite escribir elementos de UI de una manera que se parece mucho a HTML, lo que facilita la lectura y escritura de componentes de interfaz de usuario.
Transpilación: Antes de ser ejecutado por el navegador, JSX se transpila (generalmente usando Babel) a llamadas de funciones de JavaScript estándar. Por ejemplo,
<div>Hello, World!</div>
se transpila aReact.createElement('div', null, 'Hello, World!')
.Expresiones JavaScript: Dentro de JSX, puedes usar cualquier expresión de JavaScript dentro de llaves
{}
.
Uso en Otros Frameworks:
Si bien JSX es más comúnmente usado con React, también puede ser usado en otros frameworks o bibliotecas que se integren con el ecosistema de Babel. Algunos ejemplos incluyen:
Preact: Una biblioteca similar a React pero más ligera, que también soporta JSX.
Inferno: Otra biblioteca de UI rápida que puede usar JSX.
Vue.js: Aunque Vue usa templates en su mayoría, también soporta JSX si se configura el entorno adecuadamente.
Props
Las props son las propiedades de un componente. Son datos que se pasan de un componente padre a otro hijo de manera unidireccional. Por ejemplo, si tienes un componente Button
que muestra un botón, puedes pasarle una prop text
para que el botón muestre ese texto:
Prop children
children
La prop children
es una prop especial que se pasa a los componentes. Es un objeto que contiene los elementos que envuelve un componente.
Por ejemplo, si tenemos un componente Card
que muestra una tarjeta con un título y un contenido, podemos usar la prop children
para mostrar el contenido:
Y luego podemos usarlo de la siguiente forma:
Fragments
Los Fragments son una forma de agrupar elementos sin añadir un elemento extra al DOM, ya que React no permite devolver varios elementos en un componente, solo un elemento raíz.
Para crear un Fragment en React usamos el componente Fragment
:
También podemos usar la sintaxis de abreviatura:
Nota: <Fragment>
: Permite agregar ciertas propiedades como key
, lo cual es útil en casos donde se necesitan fragmentos con elementos iterados. Sin embargo la versión <>
No permite agregar key
.
Estilos en línea a un componente
Para aplicar estilos CSS en línea a un componente en React usamos la prop style
. La diferencia de cómo lo haríamos con HTML, es que en React los estilos se pasan como un objeto y no como una cadena de texto (esto puede verse más claro con los dobles corchetes, los primeros para indicar que es una expresión JavaScript, y los segundos para crear el objeto):
Además, los nombres de las propiedades CSS están en camelCase.
CSS Modules
CSS Modules es una técnica para escribir CSS en aplicaciones React (y en otros proyectos de frontend) que permite que cada archivo CSS se comporte de manera local y encapsulada por defecto. Esto ayuda a evitar conflictos de nombres de clases y estilos globales no deseados.
Características principales de CSS Modules:
Encapsulación de Estilos:
Los estilos definidos en un archivo CSS Module son locales al componente donde se importan y no se aplican globalmente. Esto evita que los estilos se filtren a otros componentes involuntariamente.
Generación de Nombres Únicos:
Cuando se compila, cada clase en un CSS Module recibe un nombre único generado automáticamente. Por ejemplo, una clase
.button
en un CSS Module podría convertirse en algo como.button_xyz123
en el CSS final, asegurando que no haya conflictos con otras clases.button
en la aplicación.
Uso en React:
Los CSS Modules se importan en un componente de React como un objeto, donde cada clave corresponde al nombre de la clase definida en el archivo CSS, y el valor es el nombre de clase generado.
Ejemplo de Uso de CSS Modules en React:
Definir el CSS Module:
Crea un archivo CSS con la extensión
.module.css
.
Importar el CSS Module en un Componente:
Importa el CSS Module en tu componente de React.
Aquí,
styles.button
se refiere a la clase.button
definida enButton.module.css
, pero será única y encapsulada.
Uso de Múltiples Clases:
Puedes combinar múltiples clases usando templates literals o el paquete
classnames
.
Ventajas de CSS Modules:
Evita conflictos globales de nombres de clases al mantener los estilos locales por defecto.
Mejor mantenimiento: facilita la gestión y organización de estilos, especialmente en aplicaciones grandes.
Soporte para variabilidad de nombres de clases: permite el uso de dinámicos y compuestos nombres de clases.
Renderizado de listas
El renderizado de listas es la forma de iterar un array de elementos y renderizar elementos de React para cada uno de ellos.
Para hacer renderizado de listas en React usamos el método map
de los arrays:
El elemento li
tiene una prop key
que es un identificador único para cada elemento. Esto es necesario para que React pueda identificar cada elemento de la lista y actualizarlo de forma eficiente. Más adelante hay una explicación más detallada sobre esto.
Esto es equivalente a:
¿Cuándo usar return
explícito?
return
explícito?Usar return
explícito dentro del map
es recomendable en las siguientes circunstancias:
Lógica más Compleja: Si necesitas realizar más cálculos, condicionales, o manipular datos antes de renderizar el elemento.
Uso de Condicionales: Si quieres condicionar qué elementos se renderizan.
Mejor Legibilidad: Cuando el contenido dentro del
map
es extenso, unreturn
explícito puede mejorar la legibilidad.
Eventos
Para pasar un parámetro a una función que maneja un evento en React podemos usar una función anónima:
Cuando el usuario hace clic en el botón, se ejecuta la función onClick
pasándole como parámetro el valor de la prop id al componente padre
.
El estado
El estado es la forma en que React guarda información de nuestro componente para escuchar cuando tenga cambios y disparar un nuevo render, y de este modo controlar los cambios en la interfaz.
El "Estado" es una de las principales herramientas que React nos proporciona para crear UI´s dinámicas y actualizadas en tiempo real.
Para crear un estado en React usamos el hook useState
:
Al usar el hook useState
este devolverá un array
de dos posiciones:
El valor del estado.
La función para cambiar el estado.
Suele usarse desestructuración para facilitar la lectura y ahorrarnos algunas líneas de código. Por otro lado, al pasarle un dato como parámetro al useState
le estamos indicando su estado inicial.
Con un componente de clase, la creación del estado sería así:
En React, "stateful" y "stateless" son términos que se refieren a dos tipos diferentes de componentes en función de cómo manejan el estado.
Stateful Components (Componentes con estado): Estos son componentes que tienen un estado interno. Pueden almacenar y modificar datos a lo largo del tiempo, lo que les permite responder a eventos y actualizar su representación en consecuencia.
Stateless Components (Componentes sin estado): Estos son componentes que no tienen un estado interno propio. No pueden almacenar datos ni responder a eventos internamente. Son funciones puras que aceptan props como entrada y devuelven elementos de React. Los componentes sin estado suelen utilizarse para representar la UI basada únicamente en las props que reciben.
Actualizar el estado de un objeto en React, debe hacerse de manera que el estado se mantenga inmutable. Ejemplo.
El operador de propagación te permite copiar las propiedades del objeto original y luego sobrescribir las propiedades específicas que deseas actualizar.
Explicación:
...prevPersona
copia todas las propiedades actuales depersona
, y luegonombre: 'Carlos'
sobrescribe la propiedadnombre
.Si estás trabajando con estados muy complejos y profundos, puedes considerar usar una biblioteca como
immer
, que facilita la gestión de la inmutabilidad.
Hooks
Desde que en React 16.8.0 se incluyeron los hooks, los componentes de funciones pueden hacer casi todo lo que los componentes de clase.
Aunque no hay una respuesta clara a esta pregunta, normalmente los componentes funcionales son más sencillos de leer y escribir y pueden tener un mejor rendimiento en general.
Además, los hooks solo se pueden usar en los componentes funcionales. Esto es importante, ya que con la creación de custom hooks podemos reutilizar la lógica y podría simplificar nuestros componentes.
Por otro lado, los componentes de clase nos permiten usar el ciclo de vida de los componentes, algo que no podemos hacer con los componentes funcionales donde solo podemos usar useEffect
.
useEffect
Los efectos son hooks que se ejecutan o actualizan únicamente si se cumplen ciertas condiciones en cada nuevo render. La condición esta dentro del array del segundo parámetro de la funcion misma useEffect.
Si el array esta vacio se ejecuta una sola vez al ser montado el componente.
Podemos ejecutar código cuando el componente se desmonta usando el hook useEffect
y dentro devolver una función con el código que queremos ejecutar. En este caso, la función que se pasa como primer parámetro del useEffect
se ejecutará cuando el componente se monte, y la función que es retornada se ejecutará cuando se desmonte.
Esto es muy útil para limpiar recursos que se hayan creado en el componente, como por ejemplo, eventos del navegador o para cancelar peticiones a APIs.
useId
useId
useId
es un hook para generar identificadores únicos que se pueden pasar a los atributos de las etiquetas HTML y es especialmente útil para accesibilidad.
Como ves en App
estamos usando el componente dos veces. Si pusieramos una id a mano, por ejemplo password
, entonces la ID no sería única y quedaría duplicada. Por eso es importante que generes la ID automáticamente con useId
.
La etiqueta aria-describedby
te permite especificar que dos etiquetas están relacionadas entre sí, puede generar una identificación única con useId donde incluso si PasswordField
aparece varias veces en la pantalla, las identificaciones generadas no chocarán.
useRef
useRef
En el siguiente ejemplo vamos a guardar la referencia en el DOM a un elemento <input>
y vamos a cambiar el foco a ese elemento cuando hacemos clic en el botón.
Creamos una referencia inputEl
con useRef
y la pasamos al elemento <input>
como prop ref
. Cuando el componente se monta, la referencia inputEl
apunta al elemento <input>
del DOM.
Para acceder al elemento del DOM, usamos la propiedad current
de la referencia.
Tambien se puede usar para Guardar referencias a funciones o callbacks: Especialmente útil en situaciones donde quieres asegurarte de que una referencia a una función no cambie entre renders, o cuando manejas eventos asincrónicos.
Ejemplo: Temporizador con useRef
para mantener la referencia del callback
Imagina que tienes un componente que ejecuta un temporizador, y quieres que el temporizador siga ejecutando una función específica que podría cambiar durante la vida del componente. Si simplemente usas la función directamente en el setInterval
, cada vez que la función cambie, el temporizador usará la versión vieja de la función. Aquí es donde useRef
puede ayudar.
Explicación del Código
useRef
para guardar la función:const savedCallback = useRef();
crea una referencia mutable que puede mantener cualquier valor. En este caso, queremos que mantenga una referencia a la funcióntick
.
Guardar la función en la referencia:
useEffect(() => { savedCallback.current = tick; }, [tick]);
actualiza la referenciasavedCallback.current
cada vez que la funcióntick
cambia. Esto asegura quesavedCallback.current
siempre tenga la versión más reciente de la funcióntick
, sin importar cuántas veces el componente se renderice.
Usar la referencia en un
setInterval
:Otro
useEffect
se encarga de crear el intervalo que ejecuta la función guardada ensavedCallback.current
cada vez que pasa eldelay
especificado. Aquí es clave que elsetInterval
utilicesavedCallback.current()
en lugar detick()
directamente. Esto permite que siempre se ejecute la versión más reciente detick
sin necesidad de recrear el intervalo cuando la función cambia.
Control del intervalo:
Los botones permiten cambiar el
delay
del intervalo para aumentar o disminuir la velocidad a la que el contador se incrementa.
Ventajas de este enfoque:
Referencias constantes:
useRef
mantiene la referencia a la función constante entre renders, lo que evita problemas con funciones obsoletas o callbacks inconsistentes en componentes complejos.Eficiencia: No se crean nuevos intervalos cada vez que el componente se renderiza. Solo se utiliza la referencia actualizada de la función, manteniendo el intervalo actual intacto.
Suscribirse a un evento
Dentro de useEffect
nos podemos suscribir a eventos del navegador, como el evento resize
para saber cuando el usuario cambia el tamaño de la ventana. Es importante que nos desuscribamos cuando el componente se desmonte para evitar fugas de memoria. Para ello, tenemos que devolver una función dentro del useEffect
que se ejecutará cuando el componente se desmonte.
Aunque normalmente los componentes de React solo cuentan con un useEffect
lo cierto es que podemos tener tantos useEffect
como queramos en un componente. Cada uno de ellos se ejecutará cuando se renderice el componente o cuando cambien las dependencias del efecto.
Cancelar una petición a una API en useEffect
useEffect
Cuando hacemos una petición a una API, podemos cancelarla para evitar que se ejecute cuando el componente se desmonte usando AbortController
como hacemos en este ejemplo:
Custom Hooks
Nos permiten abstraer parte de la lógica de nuestros componentes para su posterior reutilización.
Un hook personalizado es una función que empieza con la palabra use
y que puede utilizar otros hooks. Son ideales para reutilizar lógica en diferentes componentes. Por ejemplo, podemos crear un hook personalizado para extraer la gestión del estado de un contador:
Para usarlo en un componente:
React Context
El contexto es una forma de pasar datos a través de la jerarquía de componentes sin tener que pasar props manualmente en cada nivel.
Para crear un contexto en React usamos el hook createContext
:
Para usar el contexto, debemos envolver el árbol de componentes con el componente Provider
:
Para consumir el contexto, debemos usar el hook useContext
:
El react context ayuda asolucionar el Prop Drilling que es cuando las props de un componente padre son enviadas a sus componentes hijos, siendo estos demaciados que se torna complejo su manipulacion.
Tambien se puede crear un provider personalizado.
Portales
Los React Portals permiten que algunos componentes salgan del flujo o estructura por defecto de nuestra aplicación. Con ellos podemos crear portales para teletransportar componentes entre diferentes nodos de HTML. Los componentes vivirán en lugares diferentes de la página, lo que evitará muchos problemas de CSS (como z-index
y overflow
), pero React seguirá manteniendo control sobre ellos para comunicarles props y estados.
Mas información en https://platzi.com/blog/react-portals/
Side Effect
En JavaScript y React, un "side effect" (efecto secundario) es cualquier operación o comportamiento que ocurre fuera del alcance o flujo principal de una función o componente, afectando el estado externo o provocando cambios observables que no están directamente relacionados con la función en sí.
En JavaScript:
En JavaScript, un side effect ocurre cuando una función modifica algo fuera de su alcance local. Esto podría ser:
Modificar una variable global: Si una función cambia el valor de una variable que está fuera de su propio contexto.
Modificar una variable externa o de una función: Si una función modifica el estado de un objeto o una variable que fue pasada como argumento.
Realizar operaciones de entrada/salida: Llamadas a APIs, manipulación del DOM, operaciones de archivo, etc.
Lanzar errores o excepciones: A veces se considera un efecto secundario si la función tiene efectos colaterales al lanzar errores.
Por ejemplo:
En React:
En React, un side effect se refiere a cualquier operación que se realiza dentro de un componente que afecta algo fuera de la función de renderizado del componente. React tiene un ciclo de vida de componentes específico, y los side effects generalmente se manejan usando hooks como useEffect
.
Ejemplos de side effects en React:
Fetch de datos desde una API: Si una función de React realiza una llamada a una API para obtener datos y luego actualiza el estado con esos datos.
Manipulación directa del DOM: Aunque React se encarga de actualizar el DOM, en algunos casos se puede necesitar manipular el DOM directamente, lo cual es considerado un side effect.
Suscripciones: Establecer suscripciones o listeners que necesiten ser limpiados cuando el componente se desmonte.
Ejemplo usando useEffect
:
Aquí, la llamada a fetch
es un side effect porque ocurre fuera del ciclo de renderizado principal y afecta al estado del componente.
Last updated