javascript - validacion - ¿Dónde se debe hacer la solicitud de ajax en la aplicación Flux?
validar formulario javascript html5 (6)
Estoy creando una aplicación react.js con arquitectura de flujo y estoy tratando de averiguar dónde y cuándo se debe hacer una solicitud de datos desde el servidor. ¿Hay algún ejemplo para esto? (No es la aplicación TODO!)
Aquí está mi opinión sobre esto: http://www.thedreaming.org/2015/03/14/react-ajax/
Espero que ayude. :)
Fluxxor tiene un ejemplo de comunicación asíncrona con una API.
Esta publicación del blog habla sobre ello y se ha presentado en el blog de React.
Considero que esta es una pregunta muy importante y difícil que aún no está respondida claramente, ya que la sincronización del software frontend con el backend sigue siendo una molestia.
¿Deberían realizarse solicitudes de API en componentes JSX? ¿Víveres? ¿Otro lugar?
Realizar solicitudes en tiendas significa que si 2 tiendas necesitan los mismos datos para una acción determinada, emitirán 2 solicitudes similares (a menos que introduzcas dependencias entre tiendas, lo que realmente no me gusta )
En mi caso, he encontrado esto muy útil para poner las promesas Q como carga útil de acciones porque:
- No es necesario que mis acciones sean serializables (no llevo un registro de eventos, no necesito la función de reproducción de eventos de la fuente de eventos)
- Elimina la necesidad de tener diferentes acciones / eventos (solicitud activada / solicitud completada / solicitud fallida) y tiene que coincidir con los identificadores de correlación cuando se pueden activar solicitudes simultáneas.
- Permite que múltiples tiendas escuchen la finalización de la misma solicitud, sin introducir ninguna dependencia entre las tiendas (sin embargo, ¿puede ser mejor introducir una capa de almacenamiento en caché?)
Ajax es el mal
Creo que el Ajax se utilizará cada vez menos en un futuro próximo porque es muy difícil razonar. ¿La manera correcta? Teniendo en cuenta los dispositivos como parte del sistema distribuido, no sé de dónde se me ocurrió esta idea (quizás en este inspirador video de Chris Granger ).
Piénsalo. Ahora, para la escalabilidad, usamos sistemas distribuidos con una eventual coherencia como motores de almacenamiento (porque no podemos superar el teorema de CAP y muchas veces queremos estar disponibles). Estos sistemas no se sincronizan a través de sondear entre sí (¿excepto para las operaciones de consenso?), Sino que utilizan estructuras como CRDT y registros de eventos para que todos los miembros del sistema distribuido sean consistentes (los miembros convergerán a los mismos datos, siempre que se les dé suficiente tiempo) .
Ahora piensa en qué es un dispositivo móvil o un navegador. Es solo un miembro del sistema distribuido que puede sufrir de latencia de red y partición de red. (es decir, está utilizando su teléfono inteligente en el metro)
Si podemos crear bases de datos de partición de red y bases de datos tolerantes a la velocidad de la red (es decir, aún podemos realizar operaciones de escritura en un nodo aislado), probablemente podamos crear software de frontend (móvil o de escritorio) inspirados en estos conceptos, que funcionen bien con el modo fuera de línea admitido de la caja sin características de la aplicación indisponibilidad.
Creo que deberíamos inspirarnos a ver cómo funcionan las bases de datos para la arquitectura de nuestras aplicaciones frontend. Una cosa a tener en cuenta es que estas aplicaciones no realizan solicitudes POST y PUT y GET ajax para enviar datos entre sí, sino que utilizan registros de eventos y CRDT para garantizar la consistencia eventual.
Entonces, ¿por qué no hacer eso en la interfaz? Observe que el backend ya se está moviendo en esa dirección, con herramientas como Kafka adoptadas masivamente por los grandes jugadores. Esto está relacionado de alguna manera con Event Sourcing / CQRS / DDD también.
Revisa estos asombrosos artículos de autores de Kafka para convencerte a ti mismo:
- PROCESAMIENTO DE CORRIENTES, FUENTES DE EVENTOS, REACTIVAS, CEP ... Y TENIENDO UN SENTIDO DE TODO
- El registro: lo que todo ingeniero de software debe saber sobre la abstracción unificadora de los datos en tiempo real .
Tal vez podamos comenzar enviando comandos al servidor y recibiendo un flujo de eventos del servidor (a través de websockets por ejemplo), en lugar de disparar las solicitudes de Ajax.
Nunca me he sentido muy cómodo con las peticiones de Ajax. A medida que reaccionamos, los desarrolladores tendemos a ser programadores funcionales. Creo que es difícil razonar acerca de los datos locales que se supone que son su "fuente de verdad" de su aplicación de frontend, mientras que la fuente real de la verdad está realmente en la base de datos del servidor, y su fuente de verdad "local" ya puede estar desactualizada cuando lo reciba, y nunca convergerá a la fuente real del valor de la verdad a menos que presione un botón de actualización cojo ... ¿Es esta ingeniería?
Sin embargo, todavía es un poco difícil diseñar tal cosa por algunas razones obvias:
- Su cliente móvil / navegador tiene recursos limitados y no necesariamente puede almacenar todos los datos localmente (por lo tanto, a veces, se requiere un sondeo con un contenido pesado de solicitud ajax)
- Su cliente no debe ver todos los datos del sistema distribuido, por lo que se requiere de alguna manera filtrar los eventos que recibe por razones de seguridad.
He estado usando el ejemplo de Binary Muse del ejemplo de Fluxxor ajax . Aquí está mi ejemplo muy simple utilizando el mismo enfoque.
Tengo una tienda de productos simple , algunas acciones de productos y el componente de vista de controlador que tiene subcomponentes que responden a los cambios realizados en la tienda de productos . Por ejemplo, producto deslizante , lista de productos y componentes de búsqueda de productos .
Producto falso cliente
Aquí está el cliente falso que podría sustituir para llamar a un producto final real que devuelva productos.
var ProductClient = {
load: function(success, failure) {
setTimeout(function() {
var ITEMS = require(''../data/product-data.js'');
success(ITEMS);
}, 1000);
}
};
module.exports = ProductClient;
Tienda de productos
Aquí está la tienda de productos, obviamente esta es una tienda muy mínima.
var Fluxxor = require("fluxxor");
var store = Fluxxor.createStore({
initialize: function(options) {
this.productItems = [];
this.bindActions(
constants.LOAD_PRODUCTS_SUCCESS, this.onLoadSuccess,
constants.LOAD_PRODUCTS_FAIL, this.onLoadFail
);
},
onLoadSuccess: function(data) {
for(var i = 0; i < data.products.length; i++){
this.productItems.push(data.products[i]);
}
this.emit("change");
},
onLoadFail: function(error) {
console.log(error);
this.emit("change");
},
getState: function() {
return {
productItems: this.productItems
};
}
});
module.exports = store;
Ahora las acciones del producto, que hacen que la solicitud AJAX y, con éxito, activen la acción LOAD_PRODUCTS_SUCCESS que devuelve productos a la tienda.
Acciones del producto
var ProductClient = require("../fake-clients/product-client");
var actions = {
loadProducts: function() {
ProductClient.load(function(products) {
this.dispatch(constants.LOAD_PRODUCTS_SUCCESS, {products: products});
}.bind(this), function(error) {
this.dispatch(constants.LOAD_PRODUCTS_FAIL, {error: error});
}.bind(this));
}
};
module.exports = actions;
Entonces, llamar a this.getFlux().actions.productActions.loadProducts()
desde cualquier componente que escuche en esta tienda cargaría los productos.
Se podría imaginar acciones diferentes que respondan a las interacciones del usuario como addProduct(id)
removeProduct(id)
etc. siguiendo el mismo patrón.
Espero que el ejemplo ayude un poco, ya que me pareció un poco difícil de implementar, pero ciertamente ayudó a mantener mis tiendas 100% sincrónicas.
Puede solicitar datos en los creadores de acciones o en las tiendas. Lo importante es no manejar la respuesta directamente, sino crear una acción en la devolución de llamada de error / éxito. El manejo de la respuesta directamente en la tienda lleva a un diseño más frágil.
Respondí una pregunta relacionada aquí: Cómo manejar las llamadas api anidadas en flujo
Las acciones no deben ser cosas que causan un cambio. Se supone que son como un periódico que informa la aplicación de un cambio en el mundo exterior, y luego la aplicación responde a esa noticia. Las tiendas provocan cambios en sí mismas. Las acciones solo les informan.
Bill Fisher, creador de Flux https://.com/a/26581808/4258088
Lo que básicamente debería hacer es indicar a través de las acciones qué datos necesita. Si la tienda se informa por la acción, debe decidir si necesita recuperar algunos datos.
La tienda debe ser responsable de acumular / obtener todos los datos necesarios. Sin embargo, es importante tener en cuenta que después de que la tienda solicitó los datos y obtuvo la respuesta, debería iniciar una acción con los datos obtenidos, en lugar de que la tienda maneje / guarde la respuesta directamente.
Una tienda podría parecerse a algo como esto:
class DataStore {
constructor() {
this.data = [];
this.bindListeners({
handleDataNeeded: Action.DATA_NEEDED,
handleNewData: Action.NEW_DATA
});
}
handleDataNeeded(id) {
if(neededDataNotThereYet){
api.data.fetch(id, (err, res) => {
//Code
if(success){
Action.newData(payLoad);
}
}
}
}
handleNewData(data) {
//code that saves data and emit change
}
}
Soy un gran defensor de poner operaciones de escritura asíncronas en los creadores de acciones y operaciones de lectura asíncronas en la tienda. El objetivo es mantener el código de modificación del estado de la tienda en controladores de acción totalmente sincrónicos; esto los hace fáciles de razonar y de prueba unitaria. Para evitar múltiples solicitudes simultáneas al mismo punto final (por ejemplo, lectura doble), moveré el procesamiento de la solicitud real a un módulo separado que utiliza promesas para evitar las solicitudes múltiples; por ejemplo:
class MyResourceDAO {
get(id) {
if (!this.promises[id]) {
this.promises[id] = new Promise((resolve, reject) => {
// ajax handling here...
});
}
return this.promises[id];
}
}
Mientras que las lecturas en la tienda implican funciones asíncronas, hay una advertencia importante de que las tiendas no se actualizan en los controladores asíncronos, sino que activan una acción y solo activan una acción cuando llega la respuesta. Los manejadores de esta acción terminan haciendo la modificación del estado real.
Por ejemplo, un componente podría hacer:
getInitialState() {
return { data: myStore.getSomeData(this.props.id) };
}
La tienda tendría un método implementado, tal vez, algo como esto:
class Store {
getSomeData(id) {
if (!this.cache[id]) {
MyResurceDAO.get(id).then(this.updateFromServer);
this.cache[id] = LOADING_TOKEN;
// LOADING_TOKEN is a unique value of some kind
// that the component can use to know that the
// value is not yet available.
}
return this.cache[id];
}
updateFromServer(response) {
fluxDispatcher.dispatch({
type: "DATA_FROM_SERVER",
payload: {id: response.id, data: response}
});
}
// this handles the "DATA_FROM_SERVER" action
handleDataFromServer(action) {
this.cache[action.payload.id] = action.payload.data;
this.emit("change"); // or whatever you do to re-render your app
}
}