Я створюю додаток react.js з архітектурою потоку, і я намагаюся зрозуміти, де і коли слід робити запит на дані з сервера. Чи є приклад для цього. (Не додаток TODO!)
Я створюю додаток react.js з архітектурою потоку, і я намагаюся зрозуміти, де і коли слід робити запит на дані з сервера. Чи є приклад для цього. (Не додаток TODO!)
Відповіді:
Я великий прихильник введення операцій запису асинхронізу в творці дій та асинхронних операцій читання в магазині. Метою є збереження коду зміни стану зберігання у повністю синхронних обробниках дій; це робить їх простими в обґрунтуванні і простими в одиничному тесті. З метою запобігання декількох одночасних запитів до однієї кінцевої точки (наприклад, подвійне читання), я переміщу фактичну обробку запиту в окремий модуль, який використовує обіцянки для запобігання декількох запитів; наприклад:
class MyResourceDAO {
get(id) {
if (!this.promises[id]) {
this.promises[id] = new Promise((resolve, reject) => {
// ajax handling here...
});
}
return this.promises[id];
}
}
У той час як читає в магазині включають асинхронні функції, є важливе застереження , що в магазинах не оновлювати себе в обробниках асинхронних, але замість того, щоб стріляти дію і тільки вогонь дію , коли приходить відповідь. Обробники цієї дії в кінцевому підсумку роблять фактичну модифікацію стану.
Наприклад, компонент може:
getInitialState() {
return { data: myStore.getSomeData(this.props.id) };
}
У магазині був би реалізований метод, можливо, щось подібне:
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
}
}
flux
його вводять у магазини після будівництва, тому немає жодного чудового способу отримати дії в методі ініціалізації. Ви можете знайти кілька хороших ідей від ізоморофних потоків вух Yahoo; це те, що Fluxxor v2 має підтримувати краще. Не соромтеся написати мені електронну пошту, якщо ви хочете поговорити про це більше.
data: result
має бути data : data
, правда? немає result
. можливо краще перейменувати параметр даних для корисного навантаження або щось подібне.
Fluxxor має приклад зв'язку з асинхронністю з API.
Ця публікація в блозі розповідає про це і була розміщена в блозі React.
Я вважаю це дуже важливим і складним питанням, на яке ще не знайдено чіткого відповіді, оскільки синхронізація програмного забезпечення в інтерфейсі із заднім днем все ще біль.
Чи слід робити запити API в компоненти JSX? Магазини? Інше місце?
Виконання запитів у магазинах означає, що якщо 2 магазинам потрібні однакові дані для певної дії, вони видадуть 2 подібних запиту (якщо ви не введете залежності між магазинами, що мені дуже не подобається )
У моєму випадку я вважаю це дуже зручним, щоб ставити обіцянки Q як корисне навантаження дій, оскільки:
Аякс - ЗЛИВ
Я думаю, що Ajax найближчим часом буде все менше використовуватися, тому що це дуже важко міркувати. Правильний шлях? Розглядаючи пристрої як частину розподіленої системи, я не знаю, де я вперше зіткнувся з цією ідеєю (можливо, у цьому надихаючому відео Кріса Грейнджера ).
Подумай над цим. Тепер для масштабованості ми використовуємо розподілені системи з можливою послідовністю як двигуни зберігання (оскільки ми не можемо перемогти теорему CAP і часто хочемо бути доступними). Ці системи не синхронізуються через опитування один одного (за винятком можливо консенсусних операцій?), А скоріше використовують структури, такі як CRDT та журнали подій, щоб змусити всіх членів розподіленої системи в кінцевому підсумку (члени зближуватимуться з тими ж даними, даючи достатньо часу) .
Тепер подумайте, що таке мобільний пристрій чи браузер. Це просто член розподіленої системи, який може зазнати затримок у мережі та розділення мережі. (тобто ви використовуєте свій смартфон у метро)
Якщо ми можемо створити мережеві розділи та бази даних, що мають толерантність до швидкості мережі (я маю на увазі, що ми можемо виконувати операції запису на ізольований вузол), ми можемо, можливо, створити програмне забезпечення для фронтальних програм (мобільний або настільний), натхненні цими концепціями, які добре працюють з офлайн-режимом, який підтримується вікна без додатків, функцій програми немає.
Я думаю, що ми повинні наснажити себе тим, як бази даних працюють над архітектурою наших прикладних програм. Слід зауважити, що ці програми не виконують запити POST та PUT та GET ajax для надсилання даних один одному, а скоріше використовують журнали подій та CRDT для забезпечення можливої послідовності.
То чому б цього не зробити на фронталі? Зауважте, що бекенд вже рухається в цьому напрямку, інструменти на зразок Кафки масово приймаються великими гравцями. Це так чи інакше пов'язане з подіями Sourcing / CQRS / DDD.
Перевірте ці чудові статті авторів Kafka, щоб переконати себе:
Можливо, ми можемо почати, надсилаючи команди на сервер та отримуючи потік подій сервера (через веб-розетки для зразка), замість того, щоб запускати запити Ajax.
Мені ніколи не було дуже комфортно з проханнями Ajax. Як ми реагуємо, розробники, як правило, є функціональними програмістами. Я думаю, що важко міркувати про місцеві дані, які повинні бути вашим "джерелом істини" вашого додатка для інтерфейсу, в той час як справжнє джерело істини фактично знаходиться на базі даних сервера, а ваше "локальне" джерело правди вже може бути застарілим коли ви отримаєте його, і ніколи не зійдеться на реальне джерело значення істини, якщо ви не натиснете якусь кульгаву кнопку Refresh ... Це інженерія?
Однак все-таки трохи важко спроектувати таку річ з явних причин:
this.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
Ви можете зателефонувати за інформацією або в автори дій, або в магазини. Важливим є не обробляти відповідь безпосередньо, а створювати дію в зворотному / виклику помилок / успіх. Поводження з відповіддю безпосередньо в магазині призводить до більш крихкого дизайну.
Я використовую приклад Бінарної Музи з прикладу Fjaxxor ajax . Ось мій дуже простий приклад, що використовує той самий підхід.
У мене є простий у магазині продуктів деякі дії з продуктом і компонент перегляду контролера, який містить підкомпоненти, які реагують на зміни, внесені в магазин товарів . Наприклад продукт слайдер , продукт-лист і продукт-пошук компоненти.
Підроблений клієнт продукту
Ось підроблений клієнт, якого ви можете замінити для виклику продуктів, що повертаються в кінцевій точці.
var ProductClient = {
load: function(success, failure) {
setTimeout(function() {
var ITEMS = require('../data/product-data.js');
success(ITEMS);
}, 1000);
}
};
module.exports = ProductClient;
Магазин товарів
Ось магазин продуктів, очевидно, це дуже мінімальний магазин.
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;
Тепер дії з продуктом, які роблять запит AJAX та успішно запускають дію LOAD_PRODUCTS_SUCCESS, повертаючи продукти в магазин.
Дії продукту
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;
Тому дзвінки this.getFlux().actions.productActions.loadProducts()
з будь-якого компонента, який слухає цей магазин, завантажують продукти.
Ви можете уявити собі різні дії, які реагували б на взаємодію користувачів, наприклад addProduct(id)
removeProduct(id)
тощо ... слідуючи тій же схемі.
Сподіваюсь, що цей приклад трохи допомагає, оскільки я вважаю це трохи складним у здійсненні, але, безумовно, допомагав підтримувати магазини на 100% синхронними.
Я відповів на відповідне запитання тут: Як обробляти вкладені дзвінки api в потоці
Дії не повинні бути речами, які викликають зміни. Вони повинні бути як газета, яка інформує про застосування зміни у зовнішньому світі, а потім додаток відповідає на цю новину. Магазини викликають зміни в собі. Дії просто інформують їх.
Білл Фішер, творець Flux https://stackoverflow.com/a/26581808/4258088
Те, що ви в основному повинні робити, - це вказувати через дії, які дані вам потрібні. Якщо магазин отримує інформацію про дію, він повинен вирішити, чи потрібно отримувати деякі дані.
Магазин повинен відповідати за накопичення / отримання всіх необхідних даних. Важливо зазначити, що після того, як магазин запитав дані та отримав відповідь, він повинен викликати саму дію з отриманими даними, на відміну від роботи магазину / збереження відповіді безпосередньо.
Магазини можуть виглядати приблизно так:
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
}
}
Ось я сприймаю це: http://www.thedreaming.org/2015/03/14/react-ajax/
Сподіваюся, що це допомагає. :)