ovejas medio mateo los lobos envio como javascript reactjs reactjs-flux

javascript - medio - mateo 10 16



Cómo evitar el envío en medio de un envío (5)

En mi caso, obtengo datos a través de las acciones / creadores de acciones. La tienda es solo un lugar de volcado que recibe la carga útil de una acción.

Esto significa que me gustaría "fetchall" en una acción y luego pasar el resultado a la tienda que hará cualquier cosa con él y luego emitirá un evento de cambio.

Algunas personas consideran usar tiendas como yo, otras piensan como tú. Algunas personas en Facebook usan "mi" enfoque:

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/utils/ChatWebAPIUtils.js#L51

Creo que probablemente evitaría que el problema de envío tratara sus tiendas de esta manera, pero puedo estar equivocado.

Una discusión interesante es esta: https://groups.google.com/forum/#!topic/reactjs/jBPHH4Q-8Sc

donde Jing Chen (ingeniera de Facebook) explica lo que ella piensa acerca de cómo usar las tiendas.

Dentro de mi aplicación React con arquitectura de Flux, estoy recuperando datos de una tienda y me gustaría crear una acción para solicitar esa información si no existe. Sin embargo, me estoy encontrando con un error donde el despachador ya está despachando

Mi código deseado es algo como:

getAll: function(options) { options = options || {}; var key = JSON.stringify(options); var ratings = _data.ratings[key]; if (!ratings) { RatingActions.fetchAll(options); } return ratings || []; }

Sin embargo, falla intermitentemente cuando el despachador ya está despachando una acción, con el mensaje Invariant Violation: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. . A menudo hago solicitudes en respuesta a un cambio en el estado de la aplicación (por ejemplo, rango de fechas). Mi componente donde realizo la solicitud, en respuesta a un evento de cambio desde la AppStore tiene lo siguiente:

getStateFromStores: function() { var dateOptions = { startDate: AppStore.getStartISOString(), endDate: AppStore.getEndISOString() }; return { ratings: RatingStore.getAll(dateOptions), }; },

Soy consciente de que el encadenamiento de eventos es un antipatrón de Flux, pero no estoy seguro de qué arquitectura es mejor para recuperar datos cuando aún no existe. Actualmente estoy usando este terrible hack:

getAll: function(options) { options = options || {}; var key = JSON.stringify(options); var ratings = _data.ratings[key]; if (!ratings) { setTimeout(function() { if (!RatingActions.dispatcher.isDispatching()) { RatingActions.fetchAll(options); } }, 0); } return ratings || []; },

¿Cuál sería una mejor arquitectura que evite el encadenamiento de eventos o el error del despachador? ¿Es esto realmente un encadenamiento de eventos? Solo quiero cambiar los datos en función de los parámetros que ha establecido la aplicación.

¡Gracias!


La razón por la que recibe un envío en medio de un envío anterior, es que su tienda distribuye una acción (invoca a un creador de acción) de forma síncrona en el controlador para otra acción. El despachador está despachando técnicamente hasta que se hayan ejecutado todas sus devoluciones de llamada registradas. Por lo tanto, si envía una nueva acción de cualquiera de las devoluciones de llamada registradas, obtendrá ese error.

Sin embargo, si realiza algún trabajo asíncrono, por ejemplo, realiza una solicitud ajax, aún puede enviar una acción en las devoluciones de llamada ajax , o la devolución de llamada asíncrona en general. Esto funciona, ya que tan pronto como se invoca la función asíncrona, por definición continúa de inmediato la ejecución de la función y coloca la devolución de llamada en la cola de eventos.

Como lo señaló Amida y en los comentarios de esa respuesta, es una cuestión de elección si realizar solicitudes ajax de la tienda en respuesta a una acción, o si hacerlo en la tienda. La clave es que una tienda solo debe mutar su estado en respuesta a una acción , no en una devolución de llamada ajax / async.

En su caso particular, esto sería ejemplificado por algo como esto para la devolución de llamada registrada de su tienda, si prefiere hacer las llamadas ajax desde la tienda:

onGetAll: function(options) { // ...do some work request(ajaxOptions) // example for some promise-based ajax lib .then(function(data) { getAllSuccessAction(data); // run after dispatch }) .error(function(data) { getAllFailedAction(data); // run after dispatch }); // this will be immediately run during getAllAction dispatch return this.state[options]; }, onGetAllSuccess: function(data) { // update state or something and then trigger change event, or whatever }, onGetAllFailed: function(data) { // handle failure somehow }

O simplemente puede poner la llamada ajax en su creador de acciones y enviar las acciones "éxito / error" desde allí.


Mi error en particular estaba ocurriendo porque mis tiendas emitieron su evento de cambio durante el despacho de la acción, mientras aún circulaba entre los oyentes. Esto significó que cualquier oyente (es decir, componentes) que luego activara una acción debido a un cambio de datos en la tienda interrumpiría el envío. Lo arreglé emitiendo el evento de cambio después de que se hubiera completado el envío.

Así que esto:

this.emit(CHANGE_EVENT);

Convirtió

var self = this; setTimeout(function() { // Run after dispatcher has finished self.emit(CHANGE_EVENT); }, 0);

Aún un poco hacky (probablemente se reescriba, por lo que no requiere un setTimeout ). Abierto a soluciones que aborden el problema arquitectónico, en lugar de este detalle de implementación.


Puede usar la función waitFor() lugar de setTimeout

Por ejemplo, tiene 2 tiendas registradas en el mismo distribuidor y tiene una tienda en espera. Para que la otra tienda procese primero la acción, la que está en espera puede actualizarse después y enviar el evento de cambio. Ver waitFor() documentos Flux


puede utilizar la opción "aplazar" en el despachador. En tu caso sería como:

RatingActions.fetchAll.defer(options);