Las diferencias entre Componentes Controlados y No-Controlados en React

Tiempo
~8m

React es una librería para la creación y manejo de interfaces por medio de la creación y manipulación de componentes. Estos componentes son los bloques básicos de construcción.

Un componente en React se encarga de definir qué se debe renderizar en pantalla, puede recibir argumentos llamados props y mantener su propio estado, así como también contener otros componentes, creando así un árbol de componentes.

React define dos tipos de componentes: Controlados y No-Controlados. En este artículo revisaremos las diferencias entre estas dos categorías.

Uno de los casos esenciales en donde aparece esta diferenciación de componentes controlados y no-controlados es cuando se utilizan elementos de formulario (sin necesidad de pertenecer a un formulario) como input, textarea, checkbox, etc.

Estos elementos tienen un control interno de su estado otorgado por la propia implementación de HTML en el navegador, un input es capaz de mantener el valor escrito por el usuario y re-renderizar su contenido acorde al evento de escritura, es decir, mantiene un estado interno.

Conocer cuando utilizar cada una de estos tipos de componentes te permitirá definir la estructura de tu aplicación y del estado de la misma de una mejor manera simplificando cuando es necesario o incluso definir el uso de una librería de terceros en caso de ser necesario.

Este es el ejemplo que usaremos como parte del artículo:

Prerrequisitos

Estaremos revisando Componentes Controlados vs No-Controlados en React. Puedes sacar más provecho de este artículo si entiendes cómo funcionan los elementos de formulario HTML y como React maneja el estado utilizando el hook useState.

Algunos recursos que puedes utilizar:

Componentes Controlados

Este es el nombre que reciben aquellos componentes cuyo estado es manejado directamente por React, es decir, React le quita el control de estado a la implementación nativa del navegador y expone dicho control a ti, el desarrollador por medio de algunas simples API.

La forma en que utilizas el estado en React es por medio de la función llamada useState que es parte de la API de Hooks. La intención de esta función es almacenar en un solo lugar el estado que el componente renderizará.

Esto permite que tus componentes reaccionen al cambio de estado y se vuelvan a renderizar para reflejar dicho cambio.

Su forma de uso es sencilla:

La función recibe un argumento que representa el estado inicial, en este caso el valor 0 y retorna una pareja de elementos cuyo primer valor representa el estado actual y el segundo valor siempre será una función (que puedes llamar como quieras) que te permite actualizar dicho estado.

Utilizaremos esta funcionalidad de React para mantener una “sola fuente de la verdad” al utilizar elementos de formulario, es decir, el componente que renderiza los elementos de formulario es también quien controlará el estado de los elementos en base a las acciones del usuario.

Ciertamente esto implica escribir un poco más de código, pero también te da gran poder y flexibilidad, permitiéndote por ejemplo pasar este valor como prop a otras partes de la interfaz.

Utilicemos un elemento <input> como ejemplo: Un input controlado acepta la prop value para indicar cual es el valor actual que el input renderizará y una función tipo callback que se emite cuando el valor escrito en el <input> cambia, llamada onChange.

En este ejemplo podemos ver la implementación de lo anteriormente nombrado. Aquí el valor mostrado y obtenido por el input “vive” dentro del componente mediante el uso de useState. Este valor es actualizado cada vez que el input llama a la función onChange.

Cada vez que se escribe un nuevo carácter en el input, onChange es llamado y a su vez un nuevo cambio de estado ocurre, lo que cambia el valor de la variable de estado value que a su vez cambia el valor renderizado por el input.

Esto implica que tus datos (el estado) y tu interfaz (el input) están siempre en sincronía.

Éste método permite realizar algunas tareas como:

  • Realizar validaciones “en el momento”
  • Deshabilitar campos o botones hasta que cierto dato esté presente.
  • Utilizar diferentes formatos para representar el valor (prop value) del elemento.

Componentes No-Controlados

En el otro lado del espectro, React también permite el uso de componentes de formulario cuyo estado no es controlado por React, sino que, se mantiene en el funcionamiento nativo del navegador.

La gran diferencia con los componentes controlados, es que en este caso el elemento no es manejado por el estado de su componente padre, si no, se utiliza directamente el DOM.

Para escribir un componente no controlado conoceremos brevemente otro Hook.

En estos componentes, en vez de escribir un manejador de eventos para cada actualización de estado podemos usar un ref para obtener los valores directamente desde el DOM.

Un ref es una "válvula de escape" del flujo de datos de un componente React. El flujo normal es que las props sean la única forma en que un componente padre interactúe con los componente que renderiza. Si necesitas modificar un componente hijo, simplemente actualizas las props y este se re-renderizará.

ref te provee una forma de acceder a los nodos del DOM o elementos que son creados "on-the-fly" en el renderizado, ejemplos de uso de esto es:

  • Manejar el foco o selección de texto de un elemento
  • Inicializar animaciones de forma imperativa.
  • Integración de librerías externas no directamente compatibles con React.

Para crear un ref utilizamos el hook useRef que crea un objeto que se mantiene consistente entre diferentes renderizados del componente, es decir, cuando el ref cambia no se lanza un nuevo render.

El objeto tiene un atributo llamado current que se mantiene actualizado. Para interactuar con el DOM, puedes pasar el ref a cualquier elemento y React enlaza el valor de current con el elemento en el DOM.

Esta es quizá la forma más simple de implementar un grupo de elementos de formulario o un formulario sencillo, o si estás creando una librería para formularios.

Conclusión

Ambos métodos de implementar un formulario o elementos de formularios tienen sus méritos:

  • Los componentes no controlados son una forma directa de obtener datos desde el usuario cuando los requerimientos son sencillos
  • Componentes controlados, pueden ser más complejos de crear pero permiten implementar patrones más complejos.

Así que, revisa tus requerimientos y elige el método que más te acomode.

Si tu formulario es simple, tanto en número de elementos como en requerimientos de interfaz, los componentes no-controlados serán suficiente, solo debes considerar que tipo de feedback requieres.