Cualidades de las implementaciones de Good Flux

 

 

 

  • Register!
  • Advertise on Smashing Magazine

  • Índice
    1. Antecedentes útiles
      1. Reaccionar
      2. Flujo
    2. Presentando Lux.js
      1. Ejemplos
    3. Mantenerse fuera del camino
      1. Vistas del controlador
    4. Eliminación repetitiva
      1. Modelo repetitivo de ActionCreator
    5. Todo es una acción
      1. Ejemplos de Lux + Ajax
    6. Tiendas y sincronicidad
      1. Acciones, almacenamientos y E/S remotas de datos
    7. Juega bien con los demás
      1. Tienda Mixin
      2. Mezclador de accióncreador

    La cantidad de implementaciones de Flux disponibles puede resultar abrumadora, pero en general Jim Cowart lo considera un avance alentador. Los patrones sólidos y exitosos como Flux, por su propia naturaleza, fomentarán múltiples implementaciones. En este artículo, Jim analizará algunas de las lecciones clave que aprendió sobre React y Flux. Ya sea que sea nuevo en React y Flux, o que vaya tan lejos como para crear su propia implementación de Flux, Jim cree que no solo disfrutará este viaje, sino que también encontrará algunas preguntas estimulantes y sabiduría que puede aplicar en sus propios esfuerzos.

     

    Ha sido un año emocionante para mi equipo. El año pasado iniciamos un proyecto usando React y, a lo largo del proyecto, aprendimos mucho sobre React y Flux : los principios arquitectónicos recomendados por Facebook para las aplicaciones React. En este artículo, veremos algunas de las lecciones clave que hemos aprendido.

    Ya sea que sea nuevo en React y Flux, o que vaya tan lejos como para crear su propia implementación de Flux, creo que no solo disfrutará este viaje con nosotros, sino que también encontrará algunas preguntas que le harán reflexionar y sabiduría que podrá aplicar en sus propios esfuerzos. .

    Antecedentes útiles

    Esta publicación asume que tienes cierto nivel de familiaridad con React y Flux. ¿Ya estás familiarizado con ellos? No dude en pasar a la sección "Presentación de Lux.js". De lo contrario, recomiendo leer los enlaces a continuación.

    Reaccionar

    React es una biblioteca de JavaScript de código abierto, mantenida principalmente por Facebook, y destinada a ser utilizada en aplicaciones grandes que utilizan datos que cambian con el tiempo. Obviamente esto es especialmente útil cuando se desarrollan aplicaciones de una sola página . Si está familiarizado con el patrón modelo-vista-controlador , se considera que React es solo la vista , que maneja la interfaz de usuario en una aplicación y se puede usar junto con otras bibliotecas de JavaScript o marcos MVC más grandes. Aquí hay un resumen de alto nivel de React:

    • React se centra en las preocupaciones de visualización y no intenta ser un "marco de todo"
    • Las UI de React están construidas a partir de componentes.
    • Los componentes de React se pueden escribir usando JSX , una extensión de JavaScript basada en XML, o con JavaScript simple.
    • Los componentes de React se renderizan en un DOM virtual. Los renderizados posteriores se "diferencian" con el renderizado anterior, y se ejecuta la cantidad mínima de mutaciones DOM para parchear efectivamente el DOM y actualizarlo.

    Consulte la guía de introducción de Facebook .

    Flujo

    Flux es un patrón arquitectónico recomendado por Facebook para crear aplicaciones con React. Mientras que las opiniones de React lo empujan hacia el flujo de datos unidireccional, Flux proporciona una imagen más completa de cómo se ve realmente . Han surgido varias implementaciones de Flux ( lux.js de LeanKit , incluido), que brindan una visión fascinante de cómo los diferentes equipos abordan los desafíos que enfrentan. Un resumen de alto nivel de Flux incluiría:

    • Las aplicaciones Flux tienen tres abstracciones principales: vistas (componentes de React), tiendas y el despachador.
    • Las vistas "propagan" acciones (por ejemplo, interacción del usuario) a través del despachador.
    • El despachador se encarga de notificar la acción a las distintas tiendas.
    • Si el estado de una tienda cambia, emite un evento de cambio y las vistas que dependen de esa tienda para el estado se volverán a representar.

    Consulte la descripción general de Flux en Facebook .

     

    Presentando Lux.js

    Los desarrolladores de JavaScript crean nuevos marcos tan rápido como un político que hace promesas en un mitin de campaña. ¿Por qué entonces escribir otro marco? Me encanta este tema, aunque queda fuera del alcance de este artículo. Lux.js es una implementación de la arquitectura Flux usando React; Lo hemos adaptado para que se ajuste al conjunto específico de necesidades, habilidades y objetivos de nuestro equipo. De hecho, nuestro trabajo con lux intenta lograr un delicado equilibrio entre opiniones consistentes y flexibilidad para incluir otras bibliotecas que resuelvan mejor el problema en cuestión.

    Con el tiempo, fracasando y teniendo éxito en bastantes proyectos, hemos descubierto que las siguientes cualidades son los impulsores del éxito en nuestra propia implementación de flux:

    1. No te interpongas en el camino de React.
    2. Eliminar continuamente el texto repetitivo.
    3. Trate cada entrada como una acción.
    4. Las operaciones de la tienda deben ser sincrónicas.
    5. Facilite el juego bien con instancias que no son de Lux ni de React.

    Ejemplos

    Dmitri Voronianski creó flux-comparison , que le permite ver una comparación lado a lado de varias variantes de flujo (usando un ejemplo básico de carrito de compras). Implementé el mismo ejemplo usando lux para ayudar a ilustrar las explicaciones a lo largo del camino. Recomiendo ampliamente revisar este proyecto: es una excelente manera de familiarizarse rápidamente con varias implementaciones líderes de Flux.

    Bien, dejando todo eso fuera del camino, veamos más de cerca las cualidades que mencioné anteriormente.

    Mantenerse fuera del camino

    React hace un gran trabajo al centrarse solo en lo que pretende resolver. Al no ser prescriptivo en cosas más amplias como las comunicaciones de datos remotas (HTTP, WebSockets) y al proporcionar enlaces que le permiten incorporar bibliotecas de UI que no son de React, React le brinda la oportunidad de ensamblar las herramientas que mejor abordan las necesidades de su aplicación. Así como React se mantiene alejado de las preocupaciones que no resuelve, hemos descubierto que es igualmente importante mantenerse alejado de React. Es fácil interponerse en el camino cuando comienzas a abstraer patrones comunes en cómo usas otra biblioteca/marco detrás de tu propia API. (Nota: ¡esto no siempre es malo!) Por ejemplo, veamos los comportamientos de los componentes comunes que hemos incorporado a lux y cómo ha evolucionado nuestro uso de ellos.

    Vistas del controlador

    A menudo escuchará a los desarrolladores de React referirse a las vistas de controlador : un componente de React que generalmente se encuentra en la parte superior o cerca de la parte superior de una sección de la página, que escucha una o más tiendas en busca de cambios en su estado. A medida que las tiendas emiten eventos de cambio, la vista del controlador se actualiza con el nuevo estado y pasa los cambios a sus hijos a través de accesorios.

     

    lux proporciona un controllerViewmétodo que le devuelve un componente React capaz de escuchar las tiendas lux. Debajo del capó, lux usa mixins para darle a los componentes de React diferentes comportamientos, y el controllerViewmétodo le da a un componente tanto un storemixin (lo que lo hace capaz de escuchar tiendas) como un mixin ActionCreator (lo que lo hace capaz de publicar acciones). Por ejemplo:

    var CartContainer = lux.controllerView({ getActions: [ "cartCheckout" ], stores: { listenTo: [ "cart" ], onChange: function() { this.setState(getStateFromStores()); } }, getInitialState: function () { return getStateFromStores(); }, onCheckoutClicked: function () { var products = this.state.products; if (!products.length) { return; } this.cartCheckout(products); }, render: function () { return ( Cart products={this.state.products} total={this.state.total} onCheckoutClicked={this.onCheckoutClicked} / ); }});

    Si bien todavía nos gusta este enfoque conveniente, nos encontramos pasando al enfoque alternativo de configurar un componente React simple y pasar los lux mixins necesarios para lograr el mismo resultado. Tenga en cuenta que aquí estamos llamando React.createClassy usando la mixinsopción:

    var CartContainer = React.createClass({ mixins: [ lux.reactMixin.store, lux.reactMixin.actionCreator ], getActions: [ "cartCheckout" ], stores: { listenTo: [ "cart" ], onChange: function() { this.setState(getStateFromStores()); } }, // other methods, etc.});

    Cualquiera de los dos enfoques es válido, aunque creemos que el segundo enfoque está más fuera del alcance de React. ¿Por qué?

    • Obtenemos un componente displayNamegratis (ya que el transformador JSX usará nuestro varnombre cuando lo vea React.createClass).
    • Algunas vistas de controlador no necesitan ser ActionCreators. El segundo enfoque significa que solo podríamos aprobar el storemixin en esos casos, manteniendo las preocupaciones enfocadas. El primer enfoque siempre le da al componente ambas mezclas, incluso si no se usa.
    • No es necesario pasar explícitamente la instancia de React a lux (hecho a través de lux.initReact( React )) para que sepa cómo crear componentes.

    Nota: ¿Por qué dedicar tiempo a explicar estos dos enfoques diferentes? Se trata de mantenerse fuera del camino de React. Podemos fácilmente ser víctimas de una abstracción excesiva o insuficiente, por lo que debemos darnos espacio para adaptarnos a medida que nuestra comprensión mejora. La evolución de nuestro enfoque a lo largo del tiempo se ha informado a medida que nos preguntamos qué constituye una buena implementación de flujo. Este proceso de cuestionar y evaluar continuamente es una parte vital de la vida de cualquier biblioteca o marco.

    Eliminación repetitiva

    Según nuestra experiencia, la adopción de React y Flux ha dejado las preocupaciones sobre la infraestructura y el marco en un segundo plano para que podamos centrarnos en crear funciones para nuestra aplicación . Aun así, hay fragmentos de código molestos que tienden a aparecer con frecuencia. Por ejemplo, considere este enfoque común para cablear/descablear componentes para escuchar los eventos de cambio de la tienda:

     

    // Taken from the facebook-flux example:// https://github.com/voronianski/flux-comparison/blob/master/facebook-flux/js/components/CartContainer.jsxvar CartContainer = React.createClass({ // only showing the methods we're interested in componentDidMount: function () { CartStore.addChangeListener(this._onChange); }, componentWillUnmount: function () { CartStore.removeChangeListener(this._onChange); }, // more methods, etc.});

    Honestamente, el impuesto estándar no es alto aquí, pero todavía está presente. Dado que los mixins pueden proporcionar métodos de ciclo de vida de los componentes, lo hicimos automático cuando se incluyen los mixins lux:

    var ProductsListContainer = React.createClass({ mixins: [ lux.reactMixin.store ], stores: { listenTo: [ "products" ], onChange: function() { this.setState(getAllProducts()); } }, // more methods, etc.});

    Cuando nuestro ProductsListContainerse levante, estará listo para escuchar cualquiera de los espacios de nombres de la tienda proporcionados en la stores.listenTomatriz, y esas suscripciones se eliminarán si el componente se desmonta. ¡Adiós repetitivo!

    Modelo repetitivo de ActionCreator

    En las aplicaciones Flux, normalmente verás módulos ActionCreator dedicados como este:

    // snippet from: https://github.com/voronianski/flux-comparison/blob/master/facebook-flux/js/actions/ActionCreators.jsvar ActionsCreators = exports;ActionsCreators.receiveProducts = function (products) { AppDispatcher.handleServerAction({ type: ActionTypes.RECEIVE_PRODUCTS, products: products });};ActionsCreators.addToCart = function (product) { AppDispatcher.handleViewAction({ type: ActionTypes.ADD_TO_CART, product: product });};

    Como preguntábamos regularmente qué código repetido podíamos eliminar y reemplazar con la convención, las API de ActionCreator seguían apareciendo. En nuestro caso, utilizamos postal.js para la comunicación entre ActionCreators y el despachador (postal es una biblioteca de bus de mensajes en memoria que proporciona una funcionalidad avanzada de publicación/suscripción). El 99,9% de las veces, un método ActionCreator publicó un mensaje de acción sin comportamiento adicional. Las cosas evolucionaron con el tiempo de esta manera:

    // The very early days// `actionChannel` is a ref to a postal channel dedicated to lux Actionsvar ActionCreators = { addToCart: function() { actionChannel.publish( { topic: "execute.addToCart", data: { actionType: ActionTypes.ADD_TO_CART, actionArgs: arguments } } ); }};

    Esto fue muy rápidamente resumido en un mixin de ActionCreator para permitir esto:

    // The early-ish daysvar ActionCreators = lux.actionCreator({ addToCart: function( product ) { this.publishAction( ActionTypes.ADD_TO_CART, product ); }});

    Notarás dos cosas en el código anterior: primero, el uso de lux.actionCreator, que se mezcla lux.mixin.actionCreatorcon el objetivo; y segundo, el publishActionmétodo (proporcionado por el mixin). Camas articuladas

    Al mismo tiempo que usábamos el enfoque mixin anterior, habíamos caído en la práctica de tener nombres de controladores coincidentes en nuestras tiendas (el nombre del método del controlador coincidía con el tipo de acción). Por ejemplo, aquí hay una tienda lux que maneja la addToCartacción:

     

    var ProductStore = new lux.Store( { state: { products: [] }, namespace: "products", handlers: { addToCart: function( product ) { var prod = this.getState().products.find( function( p ) { return p.id === product.id; } ); prod.inventory = prod.inventory 0 ? prod.inventory - 1 : 0; } }, // other methods, etc.} );

    Hacer coincidir los nombres de los tipos de acción y los nombres de los controladores de tienda hizo que la conexión convencional fuera muy simple, pero vimos otra área en la que podíamos eliminar el texto repetitivo: si el 99% de nuestras implementaciones de la API ActionCreator acaban de publicar un mensaje, ¿por qué no inferir la creación de las API ActionCreator en función de qué? ¿Lo manejan las tiendas? Así lo hicimos, sin dejar de permitir implementaciones personalizadas de los métodos ActionCreator cuando fuera necesario. Por ejemplo, cuando se crea la instancia de la tienda en el fragmento anterior, lux verá que maneja una addToCartacción. Si aún no se ha definido una API ActionCreator para esta acción en lux.actions, lux creará una, con el comportamiento predeterminado de publicar el mensaje de acción.

    Adoptar este enfoque significa que nuestros componentes pueden especificar qué métodos ActionCreator desean en un estilo a la carta. En el siguiente fragmento, nuestro ProductItemContainer utiliza el lux.reactMixin.actionCreatormixin, que busca una getActionsmatriz y proporciona las acciones especificadas como métodos de nivel superior en el componente. Puede ver que estamos usando el addToCartmétodo ActionCreator en el onAddToCartClickedmétodo del controlador.

    var ProductItemContainer = React.createClass({ mixins: [ lux.reactMixin.actionCreator ], getActions: [ "addToCart" ], onAddToCartClicked: function () { this.addToCart(this.props.product); }, render: function () { return ( ProductItem product={this.props.product} onAddToCartClicked={this.onAddToCartClicked} / ); }});

    Como ocurre con cualquier convención, existen compensaciones. La composición es un aspecto importante de las API de ActionCreator. Deben modelarse por separado de los componentes que los utilizan. Hasta ahora, creemos que este enfoque sostiene eso, al tiempo que cambia parte de la naturaleza explícita (por ejemplo, mantener ActionCreators en su propio módulo) por flexibilidad y concisión.

    Todo es una acción

    Dado que este comportamiento de proporcionar API de ActionCreator se resumió en un mixin, hizo posible que tanto los componentes de React como las instancias que no son de lux/React usaran el mixin. Mi equipo ha estado aprovechando esto cuando se trata de cosas como API de datos remotos. Estamos utilizando un cliente hipermedia llamado halon , que entiende cómo consumir nuestros recursos hipermedia utilizando una versión extendida de HAL (Hypermedia Application Language, una especificación abierta para definir la estructura de los recursos HTTP). Cubrir hipermedia está más allá del alcance de este artículo, pero existen varios buenos recursos si está interesado en aprender más. Nuestro contenedor del lado del cliente para halon utiliza lux y mixins para que no solo pueda publicar acciones, sino también manejarlas.actionCreatoractionListener

     

    Lo abordamos de esta manera porque creemos que cada entrada , ya sea entrada del usuario o ejecución asincrónica en cola (a través de Ajax, postMessage, WebSockets, etc.), debe ingresarse al cliente como una acción . Si se ha mantenido al tanto de alguna de las discusiones de React a lo largo del tiempo, podría estar pensando: "Jim, Facebook está de acuerdo con llamar al despacho directamente en una respuesta XHR, en lugar de usar otro ActionCreator". Absolutamente, y eso tiene mucho sentido cuando su implementación le da a sus módulos de utilidad (como API de datos remotos) un control para el despachador. Con lux, optamos por que la puerta de enlace al despachador fuera a través de un contrato de mensajes y eliminamos la necesidad de que el despachador sea una dependencia de cualquier módulo.

    Entonces, si cada entrada es una acción , esto significa que podríamos tener acciones en nuestro sistema que no interesan a ninguna de nuestras tiendas. Otras acciones pueden ser de interés tanto para una tienda como para nuestra API de datos remotos. El valor de cómo esto lo complementa y lo obliga a ingresar al pozo del éxito del flujo de datos unidireccional se puede ilustrar en esta imagen:

    En el escenario anterior, un usuario hizo clic en un botón de la página que generó una solicitud del servidor. Cuando el servidor responde, la respuesta se publica como una nueva acción. Si bien sabemos que las dos acciones están relacionadas, modelar las cosas de esta manera refuerza la evitación de actualizaciones en cascada, y significa que el comportamiento de su aplicación será capaz de manejar los datos que se le envían , no solo los obtenidos a través de solicitudes HTTP.

    ¿Qué pasaría si quisiéramos actualizar la interfaz de usuario para reflejar que se están cargando datos? Es tan fácil como hacer que la tienda adecuada se encargue de la misma acción:

    Otro beneficio de tratar cada entrada como una acción: facilita ver qué comportamientos son posibles en su aplicación. Por ejemplo, aquí está el resultado de llamar lux.utils.printActions():

    Lux también proporciona un método de utilidad para ver qué tiendas participarían en el manejo de una acción y en qué orden lux.utils.printStoreDepTree(actionName):

    Ejemplos de Lux + Ajax

    Hemos resistido cualquier tentación de ser demasiado prescriptivos cuando se trata de cómo interactuar con puntos finales remotos en lux. La pauta principal que seguimos es empaquetar su acceso remoto en una API fácil de usar para desarrolladores en el cliente (¡en lugar de distribuir las solicitudes Ajax por todo el código base!) y convertir ese contenedor de API en un ActionListener y un ActionCreator. Por ejemplo, veamos un par de enfoques conceptuales que puede adoptar:

    Ajax simple

    El siguiente ejemplo solo muestra las partes relevantes de cada pieza. Nuestro componente publica un mensaje de acción para la cartCheckoutacción y nuestro WebApicontenedor lo escucha. Observe que nuestro controlador de respuesta para la llamada Ajax en realidad publica un nuevo mensaje de acción:

     

    // in a CartContainer.jsx modulevar CartContainer = React.createClass({ // other methods, properties, etc. onCheckoutClicked: function() { var products = this.state.products; if (!products.length) { return; } this.cartCheckout(products); }});// In a WebApi.js modulevar webApi = lux.actionCreatorListener({ handlers: { cartCheckout: function(products) { $.ajax({ url: "cart/checkout", method: "POST", data: products }).then( function(data) { this.publishAction("successCheckout", data); }.bind(this), cartErrorHandler ); } }});

    Cómo utilizamos el halón

    Una de las muchas cosas que nos encantan de los recursos hipermedia es la capacidad de descubrimiento incorporada . En lugar de tener que codificar enlaces específicos (como en el ejemplo anterior), halon nos permite seguir enlaces devueltos con recursos, por lo que la única URL que debemos saber es dónde vamos para obtener las OPCIONES. En este enfoque, nuestro módulo WebApi inicializa halon (lo que da como resultado una solicitud de OPCIONES al servidor) y la instancia resultante contendrá los recursos de nivel superior sobre los que podemos actuar, con sus "acciones" expuestas como métodos. En este caso tenemos un cartrecurso que expone una checkoutacción:

    // in a CartContainer.jsx modulevar CartContainer = React.createClass({ // other methods, properties, etc. onCheckoutClicked: function() { var products = this.state.products; if (!products.length) { return; } this.cartCheckout(products); }});// In a WebApi.js modulevar hal = halon( { root: "https://some-server.com/api", adapter: halon.jQueryAdapter( $ ), version: 1} );var webApi = lux.actionCreatorListener({ handlers: { cartCheckout: function(products) { hal.cart.checkout(products) .then( function(data) { this.publishAction("successCheckout", data); }.bind(this), cartErrorHandler ); } }});

    Tiendas y sincronicidad

    Acciones, almacenamientos y E/S remotas de datos

    Creo que un error clásico para quienes implementan sus propias implementaciones de Flux es colocar E/S de datos remotos en las tiendas. En la primera versión de lux, no sólo caí en este pozo, sino que saqué una pala dorada y cavé aún más profundo. Nuestras tiendas tenían la capacidad de realizar llamadas HTTP y, como resultado, era inevitable la necesidad de que los ciclos de envío de acciones fueran asincrónicos. Esto introdujo una oleada de efectos secundarios negativos:

    • La recuperación de datos de una tienda era una operación asincrónica, por lo que no era posible utilizar de forma sincrónica el estado de una tienda en un getInitialStatemétodo de vista del controlador.
    • Descubrimos que requerir lecturas asincrónicas del estado de la tienda desalentaba el uso de métodos auxiliares de solo lectura en las tiendas.
    • Poner E/S en las tiendas provocó que las tiendas iniciaran acciones (por ejemplo, en respuestas XHR o eventos WebSocket). Esto rápidamente socavó los beneficios del flujo de datos unidireccional. Las tiendas Flux que publican sus propias acciones podrían dar lugar a actualizaciones en cascada, ¡justo lo que queríamos evitar!

    Creo que la tentación de caer en este pozo tiene que ver con la tendencia de los frameworks del lado del cliente hasta la fecha. Los modelos del lado del cliente a menudo se tratan como cachés de escritura directa para datos del lado del servidor. Han surgido complejas herramientas de sincronización servidor/cliente, que fomentan efectivamente una especie de unión bidireccional entre la división servidor/cliente. Yoda lo dijo mejor: debes desaprender lo que has aprendido.

     

    Cuando me di cuenta de que sería mejor sincronizar las tiendas lux, leí la publicación de Reto Schläpfer " Solicitudes asíncronas con React.js y Flux, revisadas ". Había experimentado el mismo dolor y la misma comprensión. Hacer que las tiendas lux sean sincrónicas, desde el momento en que el despachador comienza a manejar una acción hasta el momento en que las tiendas emiten eventos de cambio, hizo que nuestra aplicación fuera más determinista y permitió que nuestras vistas de controlador leyeran sincrónicamente el estado de la tienda a medida que se inicializaban. Finalmente sentimos que habíamos encontrado los droides que buscábamos.

    Echemos un vistazo a una de las tiendas de lux en el ejemplo de comparación de flujo:

    var CartStore = new lux.Store( { namespace: "cart", state: { products: { } }, handlers: { addToCart: { waitFor: [ 'products' ], handler: function( product ) { var newState = this.getState(); newState.products[ product.id ] = ( newState.products[ product.id ] || assign( products.getProduct( product.id ), { quantity: 0 } ) ); newState.products[ product.id ].quantity += 1; this.setState( newState ); } }, cartCheckout: function() { this.replaceState( { products: {} } ); }, successCheckout: function( products ) { // this can be used to redirect to success page, etc. console.log( 'YOU BOUGHT:' ); if ( typeof console.table === "function" ) { console.table( products ); } else { console.log( JSON.stringify( products, null, 2 ) ); } } }, getProduct: function( id ) { return this.getState().products[ id ]; }, getAddedProducts: function() { var state = this.getState(); return Object.keys( state.products ).map( function( id ) { return state.products[ id ]; } ); }, getTotal: function() { var total = 0; var products = this.getState().products; for (var id in products) { var product = products[ id ]; total += product.price * product.quantity; } return total.toFixed( 2 ); }} );

    Una tienda lux contiene (al menos) una handlerspropiedad y un archivo namespace. Los nombres de las claves de la handlerspropiedad coinciden con el tipo de acción que manejan. De acuerdo con los principios de Flux, es posible que las tiendas lux esperen a otras tiendas antes de ejecutar su controlador. Las tiendas en las que debe esperar se pueden especificar por acción. El addToCartcontrolador anterior es un buen ejemplo. En la waitFormatriz, especifica los espacios de nombres de cualquier otra tienda en la que necesite esperar; este controlador espera en la tienda de "productos". El despachador determina el orden en el que las tiendas deben ejecutar sus controladores en tiempo de ejecución, por lo que no hay necesidad de preocuparse por administrar el pedido usted mismo en la lógica de su tienda. (Tenga en cuenta que si no necesita esperar en ninguna otra tienda, el valor del controlador puede ser solo la función del controlador en sí en lugar de la representación literal del objeto como se muestra arriba addToCart).

    También puede establecer el estado inicial en la tienda, como lo hicimos anteriormente, y proporcionar métodos de nivel superior que se utilizan para leer datos (el prototipo de la tienda lux proporciona el getState()método). Dado que los controladores de tienda se ejecutan sincrónicamente, puede leer de forma segura el estado de una tienda desde el getInitialStatemétodo de cualquier componente y puede estar seguro de que ninguna otra acción interrumpirá o mutará el estado de la tienda mientras se maneja otra acción.

    Las tiendas lux también proporcionan setStatemétodos replaceState, pero si intenta invocarlos directamente, se generará una excepción. Esos métodos sólo pueden invocarse durante un ciclo de envío; Implementamos esta opinión bastante dura para reforzar la directriz de que solo las tiendas mutan su propio estado, y eso se hace en un controlador.

    Juega bien con los demás

    Otra lección clave para nuestro equipo: debe ser sencillo para que las instancias lux y no React/no lux (externas) funcionen bien juntas. Con ese fin, lux proporciona mixins que pueden ser utilizados por instancias externas.

    Tienda Mixin

    El storemixin le permite escuchar eventos de cambio de tienda. Por ejemplo, este fragmento muestra una instancia conectada para escuchar nuestro ProductStore y CartStore:

    var storeLogger = lux.mixin({ stores: { listenTo: [ "products", "cart" ], onChange: function() { console.log( "STORE LOGGER: Received state change event" ); }, }}, lux.mixin.store);

    Mezclador de accióncreador

    El mixin actionCreator le da a la instancia un publishAction( actionName, arg1, arg2…)método. Este método maneja empaquetar los metadatos sobre la acción en una carga útil de mensaje y luego lo publica (si ha creado un ActionCreator personalizado que hace más que solo publicar el mensaje de acción, invocará ese comportamiento):

    // calling lux. 




    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Cualidades de las implementaciones de Good Flux

    Cualidades de las implementaciones de Good Flux

    Register! Advertise on Smashing Magazine Índice Antecedentes útiles

    programar

    es

    https://aprendeprogramando.es/static/images/programar-cualidades-de-las-implementaciones-de-good-flux-861-0.jpg

    2024-05-20

     

    Cualidades de las implementaciones de Good Flux
    Cualidades de las implementaciones de Good Flux

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20