Primeros pasos con la biblioteca React Javascript
Publicado: 2022-02-16Si pasas algún tiempo en el mundo de WordPress, probablemente te hayas cruzado con Zac Gordon. Zac es un profesor entusiasta y encantador que se enfoca en Javascript en WordPress. Tomó prestada la frase "Learn Javascript Deeply" de Matt Mullenweg y la convirtió en su eslogan personal.
Durante los últimos años, Zac ha producido videoclases, conferencias en línea, charlas en vivo y podcasts que se enfocan en enseñarle cómo usar Javascript en WordPress.
Estoy encantado de decir que estamos trabajando con Zac en un libro, "Reacción explicada". React es la biblioteca que el equipo de WordPress ha elegido para el nuevo editor de Gutenberg. No están solos: tanto Drupal como Magento también han elegido React.
Zac está tuiteando en vivo su progreso de escritura en @zgordon en Twitter. También puede escuchar a Zac hablar sobre React en el podcast OSTraining.
En este extracto del libro, Zac le brinda una descripción general de alto nivel de React y algunos conceptos clave.
¿Qué es Reaccionar?
Fuera de la caja, React es una biblioteca para crear interfaces de usuario.
Aunque React es una biblioteca de JavaScript, las interfaces que construye React son independientes.
Existen varias bibliotecas complementarias de React para que las interfaces que cree funcionen en el navegador, en el servidor, en aplicaciones nativas e incluso en entornos 360 y VR. En este libro nos enfocamos en trabajar con ReactDOM, la biblioteca que administra agregar las interfaces que construimos con React a los sitios web y aplicaciones del lado del cliente. ReactDomServer, ReactNative y React360 también son bibliotecas que puede explorar para usar las interfaces de React en otros entornos.
Además de proporcionar funciones auxiliares para crear interfaces, la arquitectura de React le permite manejar las interacciones con sus interfaces, ya sea que implique el manejo de eventos, llamadas API, gestión de estado, actualizaciones de la interfaz o interacciones más complejas.
React no proporciona tantas funciones auxiliares como algunos marcos de JavaScript. Esta es en gran parte la razón por la que llamamos a React una biblioteca y no un marco. Aún necesitarás escribir mucho JavaScript estándar cuando trabajes con React.
Explicación de la arquitectura de componentes de React
Un componente es una pieza de código independiente y reutilizable (creada a través de una función o clase).
React utiliza una arquitectura de componentes para crear interfaces de usuario y organizar el código. El archivo principal de una aplicación React simple puede verse así.
// Importar React y otros componentes importar React desde 'react'; importar {renderizar} desde 'react-dom'; importar encabezado desde './Header'; importar MainContent desde './MainContent'; importar pie de página desde './Pie de página'; aplicación de función () { regreso ( <div className="aplicación"> <Encabezado /> <Contenido principal /> <Pie de página /> </div> ); } ReactDOM.render( <Aplicación />, document.getElementById("raíz"));
Podemos ver aquí algunos componentes en uso. <Encabezado/>, <Contenido principal/> y <Pie de página/> son todos componentes. La función App() también es un componente y podemos ver en la última línea de este ejemplo cómo podemos usar la biblioteca ReactDOM y el método ReactDOM.render() para administrar la adición de la interfaz de usuario que construimos a una página web.
Si profundizamos en los componentes <Header />, <MainContent /> y <Footer />, es probable que veamos el uso de más componentes, así como lo que parece ser un marcado HTML.
importar React desde "react"; importar anuncio de "../anuncio"; importar logotipo desde "../assets/logo.svg"; Exportar función predeterminada Encabezado () { regreso ( <header className="aplicación-encabezado"> <Anuncio /> <img src={logotipo} className="aplicación-logotipo" alt="logotipo" /> <h1 className="app-title">Nombre del sitio</h1> </encabezado> ); }
En este componente <Header /> anterior, podemos ver que estamos incorporando otro componente llamado <Ad />. La mayoría de las aplicaciones de React contienen varias capas de anidamiento de componentes, como vemos con <App />, <Header /> y <Ad />.
También vemos el uso de elementos HTML en nuestro código React. Esto es posible gracias a una biblioteca llamada JSX, que le permite escribir "marcado HTML" directamente en su JavaScript. Dado que estamos utilizando React para crear interfaces de usuario, y las interfaces de usuario en la web implican marcado HTML, tiene sentido que veamos elementos similares a HTML dentro de nuestros componentes de interfaz de usuario. Exploraremos JSX en profundidad en este libro.
Si observamos un código de una aplicación React simple creada con React 360, la biblioteca VR de React, los componentes reales a los que llamamos serían diferentes, pero la arquitectura del componente aún está presente.
importar React desde 'react'; importar { Texto, Vista, boton vr, } de 'reaccionar-360'; clase Presentación de diapositivas extiende React.Component { // Código eliminado por brevedad regreso ( <Ver estilo={estilos.envoltorio}> <Ver estilo={estilos.controles}> <VrButton onClick={this.prevPhoto}> <Texto>{'Anterior'}</Texto> </BotónVr> <VrButton onClick={this.nextPhoto}> <Texto>{'Siguiente'}</Texto> </BotónVr> <Ver> <Estilo de texto={estilos.título}>{actual.título}</Texto> </Ver> </Ver> ); }
El código anterior crea varias capas de vistas 360 con algunos botones y texto superpuesto. Si bien es posible que el código real no tenga mucho sentido, debe quedar claro que tenemos varios componentes anidados que representan vistas, botones y texto.
Este es un buen ejemplo porque puedes ver cómo los mismos componentes se reutilizan de diferentes maneras pasándoles diferentes parámetros, o lo que React llama props. Comprender cómo pasan los datos a través de los componentes de React es importante para comprender la arquitectura de componentes típica utilizada para construir con React.
Explicación del flujo de datos de React
React sigue una convención de obtener y configurar datos en el punto más alto necesario en una jerarquía de componentes para que los datos pasen en una dirección hacia abajo a través de una aplicación. Echemos un vistazo a este ejemplo e imaginemos algunos de los tipos de datos que necesitaríamos. para varios componentes.
aplicación de función () { regreso( <Fragmento.de.Reacción> <Encabezado /> <Contenido /> <Barra lateral /> <Pie de página /> </Reaccionar.Fragmento> ); }
Es posible que algo como el nombre del sitio deba estar disponible tanto para el <Encabezado/> como para el <Pie de página/>. El contenido principal de la página en particular debería pasarse a <Content />. Es posible que algunos datos de widgets adicionales deban ir a <Sidebar />.
aplicación de función () { const siteTitle = getSiteTitle(); const widgets = getWidgets(); const mainContent = getPageContent(); regreso( <Fragmento.de.Reacción> <Encabezado título del sitio={título del sitio} /> <Contenido mainContent={mainContent} /> <Widgets de la barra lateral={widgets} /> <Pie de página Título del sitio={Título del sitio} /> </Reaccionar.Fragmento> ); }
Esta convención de inventar nombres de atributos y asignarles un valor es cómo pasamos datos a un componente.
Ahora <Header/> y <Footer/> tienen acceso al título del sitio, <Content/> tiene acceso al mainContent y <Sidebar/> tiene acceso a los widgets que necesita.
Una nota importante es que este patrón de pasar datos a un componente solo pasa los datos un nivel. Los componentes dentro de <Header /> no obtendrán acceso automáticamente a siteTitle.

encabezado de función (accesorios) { regreso( <encabezado> <p>Podemos ver {props.siteTitle} aquí.</p> <PageHeader siteTitle={props.siteTitle} /> <PáginaSubEncabezado /> </encabezado> ); }
Puede ver aquí que dentro de <Header /> podemos llamar a props.siteTitle y tener acceso al valor que le pasamos. Sin embargo, si quisiéramos tener acceso a siteTitle dentro del componente <PageHeader />, también tendríamos que pasar esa información manualmente.
Cuando un componente recibe un valor como prop, no debe modificarlo. Los accesorios deben pasar a través de un árbol de componentes como datos inmutables. Esto asegura que cualquier componente que haga referencia a un accesorio, haga referencia al mismo valor que sus componentes padre o hijo.
El valor de una propiedad solo debe cambiarse en el componente que originalmente estableció el valor de la propiedad y comenzó a pasarlo a través del árbol de componentes. En nuestro código de ejemplo anterior, el componente <App /> podría cambiar el valor de siteTitle, pero los componentes <Header /> o <PageHeader /> no deberían hacerlo.
Para comprender el flujo de cómo se actualizan los datos dinámicos en una aplicación React, se debe discutir el estado y cómo los controladores de eventos se pueden pasar como accesorios.
Explicación de los estados de los componentes de reacción
Como hemos aprendido, los datos fluyen sin cambios a través de los componentes como accesorios. Los datos se establecen en el componente más alto del árbol necesario para que todos los componentes secundarios pasen la información necesaria como accesorios.
En algunos casos, estos datos se reciben una vez y no es necesario cambiarlos. Sin embargo, en muchos casos, esos datos deben permanecer dinámicos y tener la capacidad de actualizarse en cualquier momento y hacer que esa actualización se refleje en todos los componentes secundarios.
Para realizar un seguimiento de los datos que cambian en React, tenemos un objeto de estado de React y un conjunto de funciones auxiliares para actualizar el valor del estado.
Aquí hay un ejemplo de un contador que se actualizaría solo. El valor del contador es un valor que es dinámico dentro de este componente y, por lo tanto, es un buen ejemplo de cuándo confiar en el estado. Tenga en cuenta que para crear componentes con estado, debemos usar clases de JavaScript en lugar de funciones.
Contador de clase extiende Componente { estado= { contador:0 }; manejarCuenta = () => { este.setState({ contador: este.estado.contador + 1 }); }; renderizar() { regreso ( <div> <h1>{este.estado.contador}</h1> <button onClick={this.handleCount}>¡¡Cuenta!!</button> </div> ); } }
Ahora es importante tener en cuenta que este estado tiene como alcance solo este componente. El valor de estado en el contador no estaría disponible para los componentes secundarios o principales.
Entonces, en un ejemplo más complejo, como el que se muestra a continuación, tendríamos que pasar el valor de counter down como accesorio al elemento secundario.
Contador de clase extiende Componente { estado= { contar: 0 }; manejarCuenta = () => { este.setState({ cuenta: este.estado.cuenta + 1 }); }; renderizar() { regreso ( <div> <PageHeader count={this.state.count} /> <button onClick={this.handleCount}>¡¡Cuenta!!</button> </div> ); } }
El accesorio de conteo <PageHeader /> se actualiza cada vez que actualizamos el estado en el componente <Counter />
función Encabezado de página (accesorios) { return <h1>{props.count}</h1>; }
Lo bueno de este enfoque es que cada vez que se actualiza el estado, se pasará automáticamente un nuevo valor a cualquier componente secundario con el valor de un accesorio establecido en estado.
Esto nos permite tener un único punto de verdad para los datos dinámicos. La fuente de la verdad es el valor en estado, gestionado desde un único componente. Todas las instancias de este valor en los componentes secundarios son valores inmutables recibidos como accesorios que no deben cambiarse fuera de este componente.
Los componentes que aparecen por encima de este componente en la jerarquía no tendrían acceso a estos datos, ya que solo se transmiten a través de accesorios. Vemos nuevamente por qué tratamos de establecer y administrar el estado de los componentes más altos en la jerarquía para que los datos estén disponibles para todo lo que los necesite.
Hay algunos otros patrones de arquitectura, como componentes de orden superior y la API de contexto, que eluden la necesidad de pasar manualmente toneladas de accesorios a través de su aplicación. Los exploraremos con más profundidad más adelante. Por ahora, queremos asegurarnos de que entendemos esta descripción general de alto nivel de cómo funcionan las cosas en general antes de comenzar a tomar atajos.
Actualización de estados de componentes en React
Ahora, ¿qué sucede cuando queremos activar el estado para que se actualice desde un componente secundario?
Imagine, por ejemplo, que con el ejemplo anterior queríamos tener un componente <Button /> en lugar de un botón codificado en nuestro componente principal <Counter />. Esto es bastante común en aplicaciones complejas.
La solución a esto, en el mundo de React, es pasar la función del controlador de eventos que actualiza el estado con setState down como accesorio. Luego se puede llamar desde cualquier componente secundario, pero la acción se llevará a cabo en el componente original que establece el estado y también tiene la capacidad de actualizarlo. Existen otros patrones para esto, pero este enfoque es el más básico.
Si no está familiarizado con el paso de funciones como parámetros, es JavaScript Vanilla completamente válido.
Una vez que se actualice el estado, se transmitirá a través de la jerarquía de componentes a través de los accesorios.
Aquí hay un ejemplo de cómo se vería.
Contador de clase extiende Componente { estado= { contar: 0 }; manejarCuenta = () => { este.setState({ cuenta: este.estado.cuenta + 1 }); }; renderizar() { regreso ( <div> <PageHeader count={this.state.count} /> <Button handleCount={this.handleCount} /> </div> ); } } función Encabezado de página (accesorios) { regreso( <h1>{props.count}</h1> ); } Botón de función (accesorios) { regreso( <button onClick={props.handleCount}>¡¡Cuenta!!</button> ); }
Aquí podemos ver un ejemplo simple de cómo React maneja el flujo de datos. Hay un único punto de verdad para los datos. Eso existe en estado establecido y actualizado desde un solo componente. Los datos se pasan en un flujo unidireccional hacia abajo a través de un árbol de componentes anidados a través de accesorios.
Si es necesario actualizar el estado desde un componente que no sea el que se configuró originalmente, se puede pasar un controlador de eventos al componente secundario necesario como apoyo. Esto mantiene los datos inmutables y fluyendo en una sola dirección porque incluso si un componente secundario activa un cambio, ese cambio se lleva a cabo más arriba en el componente original.
Cuando asignamos el valor de una propiedad a algo del estado, como se muestra a continuación, ese valor de la propiedad se actualizará automáticamente cada vez que cambie el estado.
<PageHeader contador={este.estado.cuenta} />
Cualquier otro componente secundario que haga referencia a ese valor prop también recibirá la actualización automáticamente. Esta es la belleza del flujo de datos en React.
Esto puede tomar un poco de tiempo para acostumbrarse dependiendo de cómo haya abordado problemas como estos con JavaScript en el pasado. Sin embargo, todo esto debería servir como un buen punto de partida para que podamos profundizar en la explicación de React.