Tworzę aplikację reag.js z architekturą Flux i próbuję dowiedzieć się, gdzie i kiedy należy złożyć żądanie danych z serwera. Czy jest na to jakiś przykład. (Nie aplikacja TODO!)
źródło
Tworzę aplikację reag.js z architekturą Flux i próbuję dowiedzieć się, gdzie i kiedy należy złożyć żądanie danych z serwera. Czy jest na to jakiś przykład. (Nie aplikacja TODO!)
Jestem wielkim zwolennikiem umieszczania operacji zapisu asynchronicznego w twórcach akcji i operacji odczytu asynchronicznego w sklepie. Celem jest utrzymanie kodu modyfikacji stanu sklepu w pełni synchronicznych modułach obsługi akcji; dzięki temu są łatwe do uzasadnienia i łatwe do przeprowadzenia testu jednostkowego. Aby zapobiec wielu jednoczesnym żądaniom do tego samego punktu końcowego (na przykład podwójne czytanie), przeniesię przetwarzanie rzeczywistych żądań do osobnego modułu, który używa obietnic, aby zapobiec wielu żądaniom; na przykład:
class MyResourceDAO {
get(id) {
if (!this.promises[id]) {
this.promises[id] = new Promise((resolve, reject) => {
// ajax handling here...
});
}
return this.promises[id];
}
}
Choć brzmi w sklepie obejmować funkcje asynchroniczne, istnieje istotne zastrzeżenie, że sklepy nie aktualizują się w teleskopowe asynchronicznych, ale zamiast strzelać działanie i tylko odpalić akcję kiedy nadejdzie odpowiedź. Procedury obsługi tej akcji kończą rzeczywistą modyfikację stanu.
Na przykład składnik może:
getInitialState() {
return { data: myStore.getSomeData(this.props.id) };
}
W sklepie może być zaimplementowana metoda, może taka:
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
wstrzyknięciu trafia do sklepów, więc nie ma świetnego sposobu na rozpoczęcie akcji metodą inicjalizacji. Możesz znaleźć dobre pomysły z izomoroficznych bibliotek strumienia Yahoo; jest to coś, co Fluxxor v2 powinien lepiej obsługiwać. Nie krępuj się napisz do mnie, jeśli chcesz porozmawiać o tym więcej.data: result
powinno byćdata : data
, prawda? Nie maresult
. być może lepiej zmienić nazwę parametru danych na ładunek lub coś w tym rodzaju.Fluxxor ma przykład asynchronicznej komunikacji z API.
Ten post na blogu mówi o tym i został opisany na blogu React.
Uważam to za bardzo ważne i trudne pytanie, na które jeszcze nie ma jednoznacznej odpowiedzi, ponieważ synchronizacja oprogramowania frontendu z backendem jest nadal uciążliwa.
Czy żądania API powinny być składane w komponentach JSX? Sklepy? Inne miejsce?
Wykonywanie żądań w sklepach oznacza, że jeśli 2 sklepy potrzebują tych samych danych dla danej akcji, wydadzą 2 podobne wymagania (chyba że wprowadzisz zależności między sklepami, których tak naprawdę nie lubię )
W moim przypadku jest to bardzo przydatne, aby umieścić obietnice Q jako ładunek działań, ponieważ:
Ajax jest ZŁY
Myślę, że Ajax będzie coraz mniej używany w najbliższej przyszłości, ponieważ bardzo trudno jest o tym myśleć. Właściwy sposób? Biorąc pod uwagę urządzenia jako część systemu rozproszonego, nie wiem, gdzie po raz pierwszy natknąłem się na ten pomysł (może w tym inspirującym filmie Chrisa Grangera ).
Pomyśl o tym. Teraz dla skalowalności używamy systemów rozproszonych z ostateczną spójnością jako mechanizmów pamięci masowej (ponieważ nie możemy pokonać twierdzenia CAP i często chcemy być dostępni). Systemy te nie synchronizują się poprzez wzajemne odpytywanie (może poza operacjami konsensusu?), Ale raczej używają struktur takich jak CRDT i dzienniki zdarzeń, aby ostatecznie wszyscy członkowie systemu rozproszonego byli spójni (członkowie zbiegną się do tych samych danych, mając wystarczająco dużo czasu) .
Teraz zastanów się, co to jest urządzenie mobilne lub przeglądarka. Jest tylko członkiem systemu rozproszonego, który może cierpieć z powodu opóźnień sieci i partycjonowania sieci. (tzn. używasz smartfona w metrze)
Jeśli uda nam się zbudować bazy danych z partycjami sieciowymi i bazami tolerującymi prędkość sieci (mam na myśli, że nadal możemy wykonywać operacje zapisu w izolowanym węźle), prawdopodobnie możemy zbudować oprogramowanie frontendowe (mobilne lub stacjonarne) zainspirowane tymi koncepcjami, które działają dobrze z obsługiwanym trybem offline opakowania bez funkcji niedostępności aplikacji.
Myślę, że powinniśmy naprawdę zainspirować się tym, w jaki sposób bazy danych pracują nad architekturą naszych aplikacji frontendowych. Należy zauważyć, że te aplikacje nie wykonują żądań POST oraz PUT i GET ajax w celu wysyłania danych do siebie, ale raczej używają dzienników zdarzeń i CRDT, aby zapewnić ostateczną spójność.
Dlaczego więc nie zrobić tego na interfejsie? Zauważ, że backend już przesuwa się w tym kierunku, a narzędzia takie jak Kafka są masowo adoptowane przez dużych graczy. Jest to również w jakiś sposób powiązane z Event Sourcing / CQRS / DDD.
Sprawdź te niesamowite artykuły od autorów Kafki, aby się przekonać:
Być może możemy zacząć od wysyłania poleceń do serwera i odbierania strumienia zdarzeń serwera (na przykład przez websockets) zamiast uruchamiania żądań Ajax.
Nigdy nie czułem się dobrze z prośbami Ajax. Gdy reagujemy, programiści są zwykle programistami funkcjonalnymi. Myślę, że trudno jest uzasadnić dane lokalne, które powinny być „źródłem prawdy” aplikacji frontendowej, podczas gdy prawdziwe źródło prawdy znajduje się w bazie danych serwera, a „lokalne” źródło prawdy może być już nieaktualne kiedy go otrzymasz, i nigdy nie zbliży się do prawdziwego źródła wartości prawdy, chyba że naciśniesz jakiś kiepski przycisk Odśwież ... Czy to inżynieria?
Nadal jednak trudno jest zaprojektować coś takiego z oczywistych powodów:
źródło
this.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
Możesz wezwać dane w kreatorze akcji lub w sklepach. Ważne jest, aby nie obsługiwać odpowiedzi bezpośrednio, ale utworzyć akcję w wywołaniu zwrotnym błędu / sukcesu. Obsługa odpowiedzi bezpośrednio w sklepie prowadzi do bardziej kruchego projektu.
źródło
Korzystam z przykładu Binary Muse z przykładu Fluxxor ajax . Oto mój bardzo prosty przykład z tym samym podejściem.
Mam prosty sklep z niektórymi akcjami produktu i komponent widoku kontrolera , który zawiera podskładniki, które wszystkie reagują na zmiany wprowadzone w sklepie produktu . Na przykład produktowej suwaka , produktowej liście i product-wyszukiwania komponentów.
Fałszywy klient produktu
Oto fałszywy klient, który możesz zastąpić wywoływaniem rzeczywistych produktów zwracających punkty końcowe.
Sklep z produktami
Oto sklep z produktami, oczywiście jest to bardzo minimalny sklep.
Teraz akcje produktu, które powodują żądanie AJAX i po pomyślnym uruchomieniu uruchamiają akcję LOAD_PRODUCTS_SUCCESS zwracającą produkty do sklepu.
Akcje produktu
Więc dzwonię
this.getFlux().actions.productActions.loadProducts()
z dowolnego komponentu słuchającego tego sklepu spowoduje załadowanie produktów.Można sobie wyobrazić różne działania, które reagowałyby na interakcje użytkownika, takie jak
addProduct(id)
removeProduct(id)
itp. ... według tego samego wzorca.Mam nadzieję, że ten przykład trochę pomoże, ponieważ uznałem, że jest to trochę trudne do wdrożenia, ale z pewnością pomogło utrzymać 100% synchronizację moich sklepów.
źródło
Odpowiedziałem na pokrewne pytanie tutaj: jak obsługiwać zagnieżdżone wywołania interfejsu API w trybie ciągłym
Bill Fisher, twórca Flux https://stackoverflow.com/a/26581808/4258088
Zasadniczo powinieneś robić, określając za pomocą działań, jakie dane potrzebujesz. Jeśli sklep zostanie poinformowany o działaniu, powinien zdecydować, czy musi pobrać jakieś dane.
Sklep powinien być odpowiedzialny za gromadzenie / pobieranie wszystkich potrzebnych danych. Należy jednak pamiętać, że po tym, jak sklep zażądał danych i otrzymał odpowiedź, powinien sam wywołać akcję z pobranymi danymi, w przeciwieństwie do bezpośredniego przetwarzania / zapisywania odpowiedzi przez sklep.
Sklepy mogą wyglądać mniej więcej tak:
źródło
Oto moje zdanie na ten temat: http://www.thedreaming.org/2015/03/14/react-ajax/
Mam nadzieję, że to pomaga. :)
źródło