Este tutorial de React.js le enseñará cómo crear una aplicación de tareas simple utilizando React JS y la arquitectura Flux.
React JS está haciendo algunas olas en la comunidad recientemente debido a sus supuestos incrementos de rendimiento con respecto a otros favoritos pesados (como Angular JS), especialmente cuando se trata de escribir listas. Como resultado, estoy interesado en cómo escribir una aplicación que sea fácil de usar para el usuario y, al mismo tiempo, despegar rápidamente. Uno de los grandes atractivos de React JS es el DOM virtual que se encuentra detrás de la escena para cada vista, y es la razón por la que se dice que React se desempeña tan bien. Cuando una vista requiere un redireccionamiento, todo se traduce en una copia virtual del DOM. Una vez que está completo, React realiza una diferencia entre el DOM virtual y el DOM real, y aplica solo los cambios que indica la comparación que indica la ecuación de la diferencia.
Entonces, ¿qué es lo que esperamos aprender al final de este artículo? Comprenderá los conceptos básicos de la construcción de múltiples vistas en React, verá un ejemplo concreto de cómo la arquitectura de Flux proporciona acceso a los datos y, finalmente, verá cómo todo se combina con una aplicación sencilla.
Flux es un método para recuperar datos de la API de su servidor mientras mantiene un desacoplamiento estricto de los componentes en el lado del cliente. Utiliza un protocolo de comunicación unidireccional para mantener una separación de preocupaciones. La aplicación todo utiliza Flux para recuperar datos de una API de servidor simulada.
- ¿Qué deberíamos aprender en la universidad en primer año para estudiantes de TI?
- ¿Qué se puede aprender jugando el juego Wordament?
- ¿Es mejor aprender de personas estúpidas en lugar de tratar de aprender de personas inteligentes e inteligentes?
- ¿Cómo revoluciona Logic Academy el proceso de enseñanza mediante la enseñanza inversa?
- ¿Aprender un idioma en línea sin un certificado vale la pena?
React JS y Flux van muy bien juntos, ya que se diseñó de esa manera, pero de ninguna manera dependen uno del otro. Como resultado, voy a dividir este artículo en la pieza React JS, que analizará cómo crear vistas y mejores prácticas, seguido de una visión detallada de cómo obtengo los datos de mi API del servidor simulado a través de Flujo.
He puesto en marcha una demostración de la aplicación todo, pero prepárese para decepcionarme, ya que es muy sencillo. Si quieres echarle un vistazo, dirígete aquí. Más interesante podría ser el código fuente completo de la aplicación todo, que he puesto a disposición en GitHub. Compruébalo aquí.
Reaccionar js
En primer lugar, si nunca has oído hablar de React JS, es un renderizador de vista con mentalidad de rendimiento hecho por los usuarios de Facebook. Muchos de los contendientes de peso pesado para los marcos MVVM tienen dificultades para procesar grandes cantidades de datos, como en listas y otros. React no tiene ese problema, ya que representa solo lo que ha cambiado. Por ejemplo, si un usuario está viendo una lista de 100 elementos renderizados con React, y él o ella modifica el tercero hacia abajo de alguna manera, solo ese elemento se vuelve a entregar, dejando los otros 99 elementos sin cambios. También utiliza lo que Facebook llama un “DOM virtual” para un mayor rendimiento al escribir virtualmente un render completo, y luego verificar la diferencia entre el render virtual y lo que realmente está en el DOM y crear un parche. React usa archivos JSX (opcionalmente) para escribir vistas, lo que significa que JavaScript y HTML pueden vivir en un solo archivo. Es un cambio de paradigma y requiere un poco de tiempo para acostumbrarse. No tiene que usar JSX para escribir vistas de React, pero es mucho más fácil que deletrear qué componentes representar, por lo que sugiero que lo use.
Reaccionar funciona fuera de clases. Para representar un poco de HTML, primero debe crear una clase React, que describa lo que debe representar. Aquí hay un ejemplo de una simple clase React.
var HelloWorld = React.createClass ({
render: function () {
return
;
}
});
React.render (new HelloWorld (), document.body);
Primero, estamos creando nuestra clase React, llamada HelloWorld . En ella, especificamos una función: render. Es lo que se llama cuando queremos representar el HTML interno, como, por ejemplo, en la línea inferior del fragmento. Notarás que la función de render en nuestra clase contiene HTML; aquí es donde JSX entra en juego. Nos permite escribir HTML dentro de nuestros archivos JavaScript en lugar de colocarlos en plantillas separadas. La última línea del fragmento indica que queremos que nuestra clase HelloWorld se represente en el cuerpo del documento.
Accesorios
Entonces, ¿qué sucede cuando queremos pasar algunos datos a nuestras clases React? El ejemplo anterior no proporciona ningún tipo de mecanismo para eso, pero este sí lo hace.
var HelloWorld = React.createClass ({
render: function () {
return
;
}
});
React.render (nuevo HelloWorld ({name: “Chris Harrington”}), document.body);
Aquí, estamos introduciendo el argumento props en la clase React, que se utiliza específicamente para pasar datos a una vista React. Cualquier cambio a una variable prop activará una nueva representación de la parte apropiada de la vista. Esos cambios pueden provenir de la propia vista, o de la vista principal o de cualquier vista secundaria que tenga nuestra vista. Esto es bastante útil, ya que nos permite pasar algunos datos entre varias vistas y tenerlos todos sincronizados. En el fragmento anterior, paso mi nombre a la clase HelloWorld , que se procesa dentro de la div usando la variable props.
Estado
var HelloWorld = React.createClass ({
getInitialState: function () {
regreso {
contador: 0
};
}
incremento: función () {
this.setState ({counter: this.state.counter + 1});
}
render: function () {
regresa
;
}
});
React.render (new HelloWorld (), document.body);
Este fragmento de código introduce la otra parte de una clase React: estado . La propiedad estatal de una clase React nos permite realizar un seguimiento de los cambios internos en la vista. Al igual que los accesorios, cualquier cambio en el estado activará una nueva representación de los elementos apropiados en la vista, con una condición: debe llamar al método setState , como se ve en la función de incremento en la clase. Siempre use setState! Sin él, sus cambios no se reflejarán en su punto de vista, que es el punto principal de usar React en primer lugar. La función getInitialState es necesaria cuando se utiliza el estado interno. Indica a la vista cuál debe ser el estado inicial. Asegúrese de incluir esta función, incluso si su estado está vacío para empezar; un estado vacío sigue siendo un estado.
Entonces, ¿cuándo usa props o estado, o incluso solo variables privadas? Los apoyos se utilizan para pasar datos entre las clases de React primarias y secundarias, y cualquier cambio en una propulsión provoca una repetición automática de la vista, tanto primaria como secundaria. Para los datos que solo son relevantes para la vista y nada más, use estado. Cualquier cambio aquí también redirige la vista. Para cualquier dato que sea pertinente para la clase pero no para la vista en sí, podría usar una variable privada, pero probablemente aún usaría el estado; Es para lo que es.
Vistas anidadas
Una de las cosas que hace que React sea tan fácil de usar es el concepto de vistas de anidamiento. Podemos procesar clases de React desde otras clases de React, como tales.
var FancyButton = React.createClass ({
render: function () {
retorna
}
});
var HelloWorld = React.createClass ({
getInitialState: function () {
regreso {
contador: 0
};
}
incremento: función () {
this.setState ({counter: this.state.counter ++});
}
render: function () {
regresa
;
}
});
Aquí, hemos abstraído el botón para incrementar el contador en una clase React separada, pasando el texto, una clase de icono (a través de Font Awesome) y un controlador de clic. Esto ilustra cómo se pueden asignar accesorios a través de clases anidadas.
Nota: Debido a que “clase” es una palabra clave restringida en JavaScript, escribir sus clases CSS en el HTML de una clase React se realiza usando el texto “nombre de clase”. Puedes ver eso en el fragmento de código anterior, donde estoy configurando la clase CSS para el ícono en el FancyButton.
Funciones de visualización construidas por el usuario
Hay algunas otras funciones que debe tener en cuenta al escribir vistas React.
- componentWillMount : esta función se llama cuando la vista se agrega a la vista principal. Se dispara cada vez que esto sucede, por lo que es un buen candidato para realizar una configuración inicial de su vista o para conectar controladores de eventos y cosas por el estilo. Será útil para implementar nuestra arquitectura Flux más adelante.
- componentWillUnmount – Opuesto a componentWillMount . Se activa cuando la vista ya no se representa en un padre. Útil para desenganchar a los manejadores de eventos.
Eche un vistazo a la documentación de React JS para obtener una lista completa de los métodos que puede implementar.
Funciones de vista predefinidas
- setState : como se mencionó anteriormente, este es el método al que llama para establecer el estado interno de su vista React. Si establece el estado directamente (es decir, this.state.foo = “bar”), su vista no se redireccionará. Como regla general, siempre use setState, como tal: this.setState ({foo: “bar”}).
- forceUpdate : este es un método conveniente para forzar a un redireccionador de la vista. Es útil para los casos en los que está actualizando algunas variables dentro de su vista que no son parte de props o estado.
Hay otros métodos que puede utilizar en la vista, pero estos son los dos que más he usado. Para obtener una lista completa, consulte la documentación de React JS.
Esos son los fundamentos detrás de React JS. Ahora voy a ver cómo funciona la arquitectura de Flux, y luego pasaremos a la aplicación de todo.
¿Quieres acelerar tu proceso de aprendizaje? Aprende a reaccionar con un experto en vivo
Flujo
La arquitectura de Flux es lo que Facebook recomienda utilizar como flujo de trabajo para recuperar datos del lado del cliente de una tienda de algún tipo en un servidor remoto. Es un flujo de datos unidireccional. En un nivel alto, un usuario inicia una acción, que la vista maneja al enviar una solicitud de datos a un almacén. A su vez, esa tienda ejecuta la solicitud y cuando se recuperan los datos, emite un evento que lo dice a todos los que están escuchando. Esos oyentes actualizan sus puntos de vista en consecuencia. Aquí están los componentes principales:
- Vista : la vista es responsable de manejar una acción por parte de un usuario, como recuperar una lista de elementos pendientes. Lo hace enviando una solicitud de datos a través del despachador.
- Despachador : el despachador tiene dos responsabilidades principales: registrar devoluciones de llamadas después de un despacho. Una tienda registrará una devolución de llamada con el despachador para que, cada vez que se envíe una acción, la tienda sea notificada y pueda verificar si necesita realizar alguna acción. Por ejemplo, una clase de TodoStore se registra con el despachador para que, cada vez que se envíe una acción para recuperar todos los pendientes, sepa cómo iniciar el proceso de obtención de datos. Se deben cumplir las acciones de despacho. Una vista envía una acción para recuperar datos a través del método de envío en el despachador. Cualquier devolución de llamada registrada con la misma clave se notifica en un envío. El método de despacho por lo general también contiene cualquier información de carga útil requerida, como una ID al recuperar un dato específico, por ejemplo.
- Almacenar : el almacén también tiene dos responsabilidades. Despertar en un envío relevante para recuperar los datos solicitados. Esto se logra mediante el registro con el despachador generalmente cuando se construye. Notificando a los oyentes de un cambio en los datos de la tienda después de una operación de recuperación, actualización o creación. Esto se hace a través del emisor de eventos.
- Emisor de eventos : el emisor de eventos es responsable de notificar a los suscriptores después de que una tienda haya completado cualquier acción de datos. A la inversa, también debe poder registrar observadores para eventos específicos. Vamos a utilizar el emisor de eventos de Node en la aplicación todo.
El despachador
El despachador es responsable de tomar solicitudes de acción desde la vista y pasarlas a la tienda (o tiendas) pertinentes. Cada tienda se registrará con el despachador para recibir actualizaciones cuando se envíe una acción. El constructor de una tienda registra una devolución de llamada con el despachador. Esto significa que cada vez que se envía una acción, esta devolución de llamada se ejecuta, pero solo se ejecutan las acciones que son pertinentes para este despachador. El paquete React Bower proporciona una clase de despachador para que lo usemos de manera inmediata, por lo que no tenemos nada que construir aquí, afortunadamente. El despachador es el primer paso en el proceso de acceso a datos en el lado del cliente.
La tienda
La tienda se utiliza para recuperar, actualizar o crear los datos una vez que se haya realizado una acción que indique lo contrario. El constructor de la tienda conectará una función de devolución de llamada a través del método de registro del despachador, que proporciona el punto de entrada de una sola vía a la tienda. El almacén luego verifica qué tipo de acción se ha enviado y, si se aplica a este almacén, ejecuta el método apropiado.
Ejemplo
Aquí hay un ejemplo rápido y sucio de cómo Flux funcionaría en una aplicación React de muestra. Más adelante, veremos la aplicación todo, que se sumergirá un poco más en la arquitectura de Flux.
var Count = React.createClass ({
getInitialState: function () {
regreso {
artículos: []
};
}
componentWillMount: function () {
emitter.on (“store-changed”, function (items) {
this.setState ({items: items});
} .bind (esto));
}
componentDidMount: function () {
dispatcher.dispatch ({type: “get-all-items”});
}
render: function () {
var items = this.state.items;
devuelve
;
}
});
var Store = function () {
dispatcher.register (función (carga útil) {
interruptor (payload.type) {
caso: “conseguir todos los elementos”:
todo esto();
descanso;
}
} .bind (esto));
this._all = function () {
$ .get (“/ some / url”, function (items) {
this._notify (elementos);
} .bind (esto));
}
this._notify = function (items) {
emitter.emit (“store-modified”, elementos);
});
};
var ItemStore = new Store ();
Nuestra vista simple simplemente representa el número de elementos en una lista. En el montaje, se engancha al emisor de eventos para ver cuándo cambia la tienda, y luego envía una solicitud para recuperar todos los elementos pendientes. La tienda ve esto porque en el momento de la construcción, se registra con el despachador para ver si hay solicitudes para obtener todos los artículos. Cuando llega la solicitud, realiza una solicitud rápida de ajax y cuando vuelve, notifica a todos los suscriptores a través del emisor de eventos. De nuevo en la vista, el estado se actualiza con la nueva lista de elementos y los visualizadores de vista, mostrando el recuento actualizado.
Todo Aplicación
Ok, ahora que tenemos un buen manejo de cómo escribir las vistas de React y de qué se trata la arquitectura de Flux, vamos a echar un vistazo a una aplicación de ejemplo de todo lo que he escrito especialmente para esta publicación. Si desea verlo en acción, vaya aquí, o si el código fuente está más arriba en su callejón, puede verlo aquí.
Obtenga Ayuda React por $ 25
Puntos de vista
Vamos a empezar con la vista principal. La aplicación solo tiene una sola página, así que aquí está.
Que hacer
“uso estricto”;
var Todo = React.createClass ({
getInitialState: function () {
regreso {
todos: []
}
}
componentWillMount: function () {
emitter.on (constants.changed, function (todos) {
this.setState ({todos: todos});
} .bind (esto));
}
componentDidMount: function () {
dispatcher.dispatch ({type: constants.all});
}
componentsWillUnmount: function () {
emitter.off (constantes.todos);
}
crear: función () {
este.refs.create.show ();
}
renderList: función (completa) {
return ;
}
render: function () {
devuelve
Lista de tareas
Incomplete
{this.renderList (false)}
Complete
{this.renderList (true)}
;
}
});
Esta es la vista principal de Todo . En el montaje, está enviando una solicitud para recuperar todos los elementos pendientes. También se conecta a un evento de cambio para la tienda de tareas pendientes para recibir una notificación cuando los artículos de la tienda se hayan actualizado después de que la solicitud enviada se haya completado con éxito. Estoy haciendo uso de la cuadrícula de Bootstrap para mostrar los elementos completos e incompletos. Hay un par de otras clases aquí que aún no se muestran: Lista y Modal . El primero es para representar la lista real, y el segundo es para agregar un nuevo elemento.
Lista
var List = React.createClass ({
renderItems: function () {
devuelve _.map (this.props.todos, function (todo) {
return ;
});
}
render: function () {
devuelve
- {this.renderItems ()}
;
}
});
La vista de lista es responsable de representar la lista de elementos, tanto completa como incompleta. Se entrega a la clase de elementos para representar el elemento real.
ít
var Item = React.createClass ({
toggle: function () {
this.props.todo.isComplete =! this.props.todo.isComplete;
dispatcher.dispatch ({type: constants.update, content: this.props.todo});
}
render: function () {
devuelve
;
}
});
La clase de elementos es responsable de dos cosas: representar el elemento en la lista y actualizar el estado de un elemento al hacer clic. La etiqueta li tiene un controlador onClick que se entrega al método de conmutación que despacha una solicitud de actualización de elementos a través del despachador. El elemento enviado contiene dos propiedades: tipo, para indicar el nombre del evento, y contenido, para indicar la carga útil del evento, que en este caso es el elemento todo.
Modal
var Modal = React.createClass ({
getInitialState: function () {
regreso {
valor: “”
};
}
componentDidMount: function () {
este. $ el = $ (this.getDOMNode ());
este. $ el.on (“hidden.bs.modal”, this.reset);
emitter.on (constants.changed, function () {
este. $ el.modal (“hide”);
} .bind (esto));
}
componentWillUnmount: function () {
emitter.off (constants.changed);
}
show: function () {
este. $ el.modal (“show”);
}
reset: function () {
this.setState ({value: “”});
}
guardar: función () {
dispatcher.dispatch ({type: constants.create, content: {name: this.state.value, isComplete: false}});
}
onChange: function (e) {
this.setState ({value: e.target.value});
}
render: function () {
return
;
}
});
La clase modal es … detallada, pero mucho de eso es el código repetitivo de Bootstrap requerido para un diálogo modal. Una vez que está fuera del camino, solo hay tres cosas que realmente nos interesan.
- La entrada de texto : la entrada de texto proporciona al usuario un área para ingresar el nombre del nuevo elemento. La unión de elementos de entrada a un valor de estado es una de las advertencias de React que analizaré en solo un segundo.
- El botón Guardar : el botón Guardar activa el método de guardar, que distribuye una acción de creación con el contenido establecido solo en un nombre y una propiedad isComplete (por defecto es falso).
- El botón de restablecimiento : el botón de restablecimiento se transfiere al método de restablecimiento, que restablece el valor del campo de entrada para que el usuario aparezca con un cuadro de entrada vacío cuando abre el cuadro de diálogo por segunda vez.
El método show de la clase Modal es interesante aquí porque resalta la propiedad refs del padre, que en este caso es la clase Todo . En la definición modal , estamos especificando un atributo ref (“modal”), que luego podemos usar para encontrar la clase representada en un momento posterior del padre. Lo estamos utilizando para mostrar el diálogo modal cuando el usuario hace clic en el botón de nuevo elemento en la clase Todo .
El enlace de datos
Enlazar la variable de estado de una vista a una entrada es un poco extraño en Reaccionar, al menos al principio. Si especificamos que un campo de texto tiene un valor como leído desde una variable de estado, también debemos especificar un controlador de eventos onChange para ese campo de texto. Si no lo hacemos, el usuario escribirá mientras se enfoca en el campo de texto y no aparecerá ningún texto. Esto se debe a que el valor del campo de texto está vinculado a un valor de estado que nunca se actualiza, por lo que no se producen cambios en la vista. Resolvemos este problema configurando el controlador onChange para que actualice la variable de estado enlazado cuando el usuario ingresa información. Es una pequeña advertencia que me lanzó a un bucle cuando empecé a escribir vistas React.
Almacenar
Aquí está la tienda utilizada para realizar un seguimiento de los cambios en la lista de tareas pendientes.
var Store = función (url, constantes) {
this._url = url;
this._collection = [];
dispatcher.register (función (carga útil) {
interruptor (payload.type) {
constantes de caso.todos:
todo esto();
descanso;
constantes de caso. actualización
this._update (payload.content);
descanso;
constantes de caso.crear:
this._create (payload.content);
descanso;
}
} .bind (esto));
this._all = function () {
$ .get (this._url) .then (function (data) {
this._collection = data;
_notificar.call (esto);
} .bind (esto));
} .bind (esto);
this._update = function (content) {
var found = _.find (this._collection, function (x) {return x.id === content.id;});
para (nombre var en encontrado)
encontrado [nombre] = contenido [nombre];
$ .post (this._url, found) .then (function () {
_notificar.call (esto);
} .bind (esto));
};
this._create = function (content) {
content.id = _.max (this._collection, function (x) {return x.id;}). id + 1;
this._collection.push (contenido);
$ .post (this._url + “/” + content.id) .then (function () {
_notificar.call (esto);
});
};
función _notificar () {
emitter.emit (constants.changed, this._collection);
}
};
var TodoStore = new Store (“fixtures / todos.json”, require (“constants”). todo);
Desde el principio, la tienda registra una función de devolución de llamada con el despachador para realizar un seguimiento de las acciones enviadas. Una vez que entra una acción, hacemos un cambio en el tipo de carga útil para determinar qué método ejecutar, luego ejecutamos el método. Una vez que se ha completado el método all, update o create, se llama al método de notificación, que simplemente emite un evento de cambio a cualquiera que escuche con la lista de elementos.
Constantes
A lo largo de toda la aplicación, estoy haciendo una referencia a un objeto de constantes. Esto es solo un objeto que contiene cadenas para cada una de las diversas acciones que están volando a través del despachador y el emisor del evento. Me parece conveniente mantener esas cuerdas abstraídas en otros lugares.
Conclusión
¡Y eso es! Como mencioné anteriormente, si desea ver la aplicación todo en acción, eche un vistazo aquí, y si está interesado en verificar el código por sí mismo, eche un vistazo aquí. ¡Gracias por leer!