Introducción a React, parte 2
Publicado: 2020-07-16Bienvenido de nuevo a nuestra introducción a React, donde te enseñamos los conceptos básicos para que entiendas cómo funciona esta tecnología y así escribir mejor código y crear mejores interfaces de usuario. En la publicación anterior, hablamos sobre cómo podrías crear componentes de React como funciones simples y puras. El mantra que repetía una y otra vez era que «un componente React es una función simple que obtiene un conjunto de propiedades ( props ) y genera algo de HTML».
La última vez que hablamos de React terminamos con la siguiente pregunta: si un componente es una función tan simple, ¿cómo podemos hacer algo útil con él? Pues bien, hoy hablaremos de la parte dinámica de React: es decir, cómo podemos hacer que un componente reaccione ante los eventos del usuario .
Configuración del entorno
La primera parte de este tutorial tenía algo de teoría pero no incluía ningún ejemplo, y me disculpo por esto; Creo que la mejor manera de aprender es haciendo, ¡así que arreglemos esto! De ahora en adelante, todo lo que te enseñaré estará basado en un ejemplo en el que trabajaremos, así que configuremos el entorno que usaremos primero.
Asumiré que tiene un sitio de WordPress en el que puede trabajar, así como el node de herramientas de desarrollo y npm . Si ese no es el caso, en esta publicación expliqué cómo puede usar Lando para crear una instalación local de WordPress, y la documentación de npm tiene todo lo que necesita saber para instalar node y npm .
Primero, creemos un complemento simple de WordPress donde tendremos nuestros componentes React. Para hacer esto, cree una carpeta llamada react-example en wp-content/plugins y coloque el archivo react-example.php dentro con el siguiente contenido:
<?php /** * Plugin Name: React Example * Description: Example. * Version: 1.0.0 */ namespace React_Example; defined( 'ABSPATH' ) or die(); function add_page() { add_menu_page( 'React Example', 'React Example', 'read', 'react-example', function () { echo '<div></div>'; } ); } add_action( 'admin_menu', __NAMESPACE__ . '\add_page' ); function enqueue_scripts() { $screen = get_current_screen(); if ( 'toplevel_page_react-example' !== $screen->id ) { return; } $dir = untrailingslashit( plugin_dir_path( __FILE__ ) ); $url = untrailingslashit( plugin_dir_url( __FILE__ ) ); if ( ! file_exists( "{$dir}/build/index.asset.php" ) ) { return; } $asset = include "{$dir}/build/index.asset.php"; wp_enqueue_script( 'react-example', "{$url}/build/index.js", $asset['dependencies'], $asset['version'], true ); } add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\enqueue_scripts' );El complemento simplemente agrega una nueva página en su panel de WordPress llamada React Example y carga un archivo JavaScript en ella. Por ahora, el resultado debería ser una página en blanco:

lo que no debería sorprender, dado que aún no hemos implementado nada en JavaScript.
Como vimos en esta publicación anterior sobre cómo agregar un botón a Gutenberg, debe ejecutar los siguientes comandos en su terminal (en la carpeta del complemento que estamos creando):
npm init npm install --save-dev @wordpress/scripts si desea poder escribir componentes React y transpilar JavaScript, simplemente siga las instrucciones en pantalla. Ah, y no olvide actualizar su archivo package.json para que incluya todos los scripts relevantes requeridos por @wordpress/scripts .
Finalmente, cree una carpeta src con el siguiente archivo index.js :
// Import dependencies import { render } from '@wordpress/element'; // Create component const HelloWorld = () => <div>Hello World</div>; // Render component in DOM const wrapper = document.getElementById( 'react-example-wrapper' ); render( <HelloWorld />, wrapper ); Ejecute npm run build (o npm run start si desea que el código se transpile automáticamente cada vez que cambie sus archivos fuente), actualice la página y listo , ya tiene todo listo:

Crear un componente funcional reactivo en React
Ahora vamos a crear un componente que reaccione a los eventos del usuario. El ejemplo que quiero que implementemos juntos es este:

un simple contador que te permite incrementar o decrementar su valor en uno usando los botones + y - respectivamente. Sé que es extremadamente simple, pero espero que lo ayude a comprender la diferencia entre el "modelo de datos" y la "interfaz de usuario", así como también lo guíe a través de la implementación de componentes dinámicos.
Mejor organización del código
Comencemos por mejorar la organización de nuestro código. El ejemplo de hoy es tan simple que es posible que desee omitir este paso, pero creo que es útil organizarse desde el principio.
En src , cree una nueva carpeta components que contendrá todos los componentes utilizados por nuestra aplicación. Dado que el ejemplo de hoy solo tiene un solo componente, Counter , todo lo que tenemos que hacer es crear un solo archivo, counter.js :
export function Counter() => ( <p>Counter</p> ); el cual, como puedes ver, simplemente exporta la función encargada de renderizar nuestro componente. Luego, modifique src/index.js para que, en lugar de representar nuestra muestra HelloWorld , importe y use nuestro nuevo componente Counter :
// Import dependencies import { render } from '@wordpress/element'; import { Counter } from './components/counter'; // Render component in DOM const wrapper = document.getElementById( 'react-example-wrapper' ); render( <Counter />, wrapper );¡Y eso es!
Implementación de un componente de contador
El objetivo de hoy es implementar un componente que realice un seguimiento del valor de un contador, que podemos aumentar o disminuir haciendo clic en un par de botones. Esto significa que nuestro componente debe tener tres cosas:
- Un elemento para mostrar el valor actual
- Un botón + para aumentar dicho valor
- A - botón para disminuirlo
La implementación de este componente es bastante sencilla:
export const Counter = ( { value } ) => ( <div> <div>Counter: <strong>{ value }</strong></div> <button>+</button> <button>-</button> </div> ); ya que sabe que su componente toma un value como uno de sus accesorios y debe incluir dos botones. Desafortunadamente, es posible que no sepa qué hacer a continuación si desea que esos botones modifiquen el valor, especialmente si tenemos en cuenta que, la última vez que hablamos de esto, le dije que "los componentes no pueden cambiar sus propiedades".
Funciones como puntales y separación de responsabilidades
Recuerda: un componente de React es una función que recibe propiedades y genera HTML. Esto quiere decir que, quien invoque esta función (o dicho de otro modo, quien utilice este componente) debe darle todos los parámetros (propiedades) que necesita.

Tu intuición ya te dijo que el valor del contador es una de las propiedades que necesita . No sabemos de dónde viene este valor (y no nos importa), pero sabemos que nuestro componente recibirá este valor. También sabe que nuestro componente Counter debe poder modificar este valor de alguna manera . En otras palabras, el componente debe ser tal que, cuando el usuario haga clic en + o - , el valor se actualice.
Si piensa por un momento en esta afirmación, rápidamente se dará cuenta de que el componente Contador no solo espera un value (de tipo número ), sino que también necesita dos accesorios adicionales de tipo función : uno que incrementa dicho valor, y otro uno que lo decrementa. En otras palabras, Counter necesita tres props diferentes:
-
value: es un número y el valor del contador (¡duh!) -
onIncrease: es una función que, cuando se invoca, aumenta el valor del contador -
onDecrease: es otra función que, cuando se invoca, disminuye el valor del contador
Si trabajamos bajo el supuesto de que a nuestro componente se le darán estos tres accesorios, el componente en sí se vuelve extremadamente simple:
export const Counter = ( { value, onIncrease, onDecrease } ) => ( <div> <div>Counter: <strong>{ value }</strong></div> <button onClick={ onIncrease }>+</button> <button onClick={ onDecrease }>-</button> </div> ); Observe cómo nuestro componente no está ejecutando las funciones que recibe (lo cual, como ya dijimos, está "prohibido" ya que desencadenaría un efecto secundario). Todo lo que hace es conectarlos al evento de click de nuestros botones. Esto significa que hemos implementado con éxito una función pura (como deberían ser todos los componentes) porque, dadas las mismas tres propiedades, el resultado siempre será el mismo HTML con las mismas "conexiones".
Desafortunadamente, si intenta usar el componente, verá que nada funciona
Dando al Componente TODOS los accesorios que necesita
¡Y no me extraña que no funcione! Cuando usamos este componente, no respetamos su contrato y no agregamos los accesorios que requiere para funcionar correctamente. Solo mira index.js :
render( <Counter />, wrapper ); ¡El contador no tiene un value ni tiene las funciones onIncrease o onDecrease !
Bueno, arreglemos esto rápidamente. Todo lo que tenemos que hacer es crear una variable que almacene el valor del contador e implementar una función que lo actualice, para que podamos usarlos en nuestro componente:
// Import dependencies import { render } from '@wordpress/element'; import { Counter } from './components/counter'; // Store value let value = 0; function setValue( newValue ) { value = newValue; } // Render component in DOM const wrapper = document.getElementById( 'react-example-wrapper' ); render( <Counter value={ value } onIncrease={ () => setValue( value + 1 ) } onDecrease={ () => setValue( value - 1 ) } />, wrapper );Gracias a esta arquitectura conseguimos separar completamente la interfaz de usuario (que es el componente) de la gestión de datos. El componente es completamente independiente de quién o cómo se almacena el valor; todo lo que le importa es que obtenga los apoyos que necesita.
Si, una vez más, actualizamos la página, verá que ahora el contador muestra un valor de contador predeterminado (es decir, 0 ), pero hacer clic en + y - aún no funciona...
Volver a renderizar el componente en la actualización
Si observa el fragmento anterior, podría pensar que las cosas deberían estar funcionando ahora. Pero claramente no lo hacen... entonces, ¿qué pasa? Bueno, hagamos una pequeña prueba. Modifica la función setValue para que, además de asignar el nuevo valor a value , también lo registre en la consola:
function setValue( newValue ) { value = newValue; console.log( 'Value is', value ); }y verifique nuevamente si las cosas funcionan como se esperaba. Simplemente abra las herramientas de desarrollo de su navegador y haga clic en sus botones:

Interesante, ¿verdad? Parece que el value se actualiza correctamente cada vez que el usuario hace clic en un botón, pero el componente nunca se actualiza.
Si desea representar un componente, debe invocar su función pura con los accesorios necesarios. Cuando cambia una propiedad, debe invocar la función pura nuevamente con el nuevo valor, para que se pueda generar el nuevo HTML. Por lo tanto, si queremos que nuestra interfaz de usuario muestre el value más reciente, debemos volver a representar manualmente el componente cada vez que se actualice el value :
// Import dependencies import { render } from '@wordpress/element'; import { Counter } from './components/counter'; // Store value let value = 0; function setValue( newValue ) { value = newValue; refreshComponent(); } // Render component in DOM const wrapper = document.getElementById( 'react-example-wrapper' ); function refreshComponent() { render( <Counter value={ value } onIncrease={ () => setValue( value + 1 ) } onDecrease={ () => setValue( value - 1 ) } />, wrapper ); } refreshComponent(); Como puede ver, simplemente creamos una nueva función llamada refreshComponent que usamos para representar el componente la primera vez y cada vez que el value se actualiza a través setValue . Esto da como resultado el comportamiento esperado:

¿En serio? ¡Representar componentes parece basura!
Si ha llegado hasta aquí siguiendo el tutorial de hoy, probablemente se haya sentido un poco decepcionado con la forma en que volvemos a renderizar los componentes de React. Y no te culpo, la última sección de este tutorial fue bastante mala. Pero eso se debe a que fue solo un ejemplo simple para mostrarle cómo puede separar los "datos" de la "IU".
Hoy has aprendido dos lecciones muy importantes :
- Los accesorios que un componente puede necesitar no son solo "datos" (como números, cadenas, matrices, objetos...) sino que también pueden ser "funciones". Esto significa que podemos conectar estas funciones a los eventos DOM para que se ejecuten “automágicamente” cuando el usuario realiza ciertas acciones y así actualizar el estado de nuestra aplicación.
- Los componentes (IU) y los datos que utilizamos son completamente independientes entre sí. A un componente de React no le importa quién o cómo se administran los accesorios que necesita. Esto significa que podemos implementar una solución de mierda para administrar y actualizar el
valuede nuestro contador y las cosas "simplemente funcionarán".
En la próxima publicación, mejoraremos esta solución y usaremos las tiendas de WordPress (que se basan en Redux) para administrar el estado de la aplicación. ¡No te lo pierdas!
Imagen destacada de Hermes Rivera en Unsplash.
