Jestem nowy w React / Redux. Używam oprogramowania pośredniczącego Fetch API w aplikacji Redux do przetwarzania interfejsów API. To ( oprogramowanie pośredniczące redux-api ). Myślę, że to dobry sposób na przetwarzanie akcji asynchronicznego interfejsu API. Ale znajduję przypadki, których nie mogę rozwiązać samodzielnie.
Jak podaje strona główna ( Lifecycle ), cykl życia API pobierania zaczyna się od wysłania akcji CALL_API i kończy się wysłaniem akcji FSA.
Mój pierwszy przypadek to pokazywanie / ukrywanie modułu wstępnego ładowania podczas pobierania interfejsów API. Oprogramowanie pośredniczące wyśle akcję FSA na początku i wyśle akcję FSA na końcu. Obie akcje są odbierane przez reduktory, które powinny wykonywać tylko normalne przetwarzanie danych. Żadnych operacji interfejsu użytkownika, żadnych więcej operacji. Może powinienem zapisać stan przetwarzania w stanie, a następnie renderować je podczas aktualizacji sklepu.
Ale jak to zrobić? Przepływ komponentu reagującego na całą stronę? co się dzieje z aktualizacją sklepu z innych działań? Chodzi mi o to, że są bardziej jak wydarzenia niż stan!
Co gorsza, co mam zrobić, gdy muszę użyć natywnego okna dialogowego potwierdzenia lub okna dialogowego ostrzeżenia w aplikacjach redux / react? Gdzie należy je umieścić, działania lub redukcje?
Wszystkiego najlepszego! Życzę odpowiedzi.
źródło
Odpowiedzi:
Nie powiedziałbym tego. Myślę, że wskaźniki ładowania to świetny przypadek interfejsu użytkownika, który można łatwo opisać jako funkcję stanu: w tym przypadku jest to zmienna boolowska. Chociaż ta odpowiedź jest prawidłowa, chciałbym podać kod, który będzie z nią zgodny.
W
async
przykładzie w repozytorium Redux reduktor aktualizuje pole o nazwieisFetching
:Komponent korzysta
connect()
z React Redux do subskrybowania stanu sklepu i zwracaisFetching
jako częśćmapStateToProps()
wartości zwracanej, więc jest dostępny w właściwościach połączonego komponentu:Wreszcie komponent używa
isFetching
właściwości wrender()
funkcji do renderowania etykiety „Ładowanie ...” (która mogłaby być zamiast tego spinner):Żadne efekty uboczne (a wyświetlenie okna dialogowego jest z pewnością efektem ubocznym) nie należą do reduktorów. Pomyśl o reduktorach jako o pasywnych „budowniczych państwa”. Tak naprawdę nie „robią” rzeczy.
Jeśli chcesz pokazać alert, zrób to z komponentu przed wywołaniem akcji lub zrób to z twórcy akcji. Zanim akcja zostanie wysłana, jest już za późno na wywołanie efektów ubocznych w odpowiedzi na nią.
Każda reguła ma wyjątek. Czasami logika efektów ubocznych jest tak skomplikowana, że w rzeczywistości chcesz połączyć je albo z określonymi typami akcji, albo z określonymi redukcjami. W takim przypadku sprawdź zaawansowane projekty, takie jak Redux Saga i Redux Loop . Rób to tylko wtedy, gdy czujesz się komfortowo z Vanilla Redux i masz prawdziwy problem z rozproszonymi efektami ubocznymi, które chcesz, aby były łatwiejsze do opanowania.
źródło
Promise.all
w jedną obietnicę, a następnie wysłać jedną akcję dla wszystkich pobierania. Lub musisz zachować wieleisFetching
zmiennych w swoim stanie.isFetching
flaga. Jest ustawiana dla każdego zestawu pobieranych obiektów. Aby to zaimplementować, możesz użyć kompozycji reduktora.RECEIVE_POSTS
nigdy nie zostanie wyzwolone, znak ładowania pozostanie na miejscu, chyba że utworzyłeś jakiś czas oczekiwania na wyświetlenieerror loading
wiadomości.Świetna odpowiedź Dan Abramov! Chcę tylko dodać, że robiłem mniej więcej dokładnie to w jednej z moich aplikacji (zachowując isFetching jako wartość logiczną) i skończyło się na tym, że musiałem uczynić ją liczbą całkowitą (która kończy się odczytaniem jako liczba zaległych żądań), aby obsługiwać wiele jednoczesnych upraszanie.
z wartością logiczną:
żądanie 1 zaczyna się -> spinner włączony -> żądanie 2 się zaczyna -> żądanie 1 się kończy -> spinner wyłączony -> żądanie 2 się kończy
z liczbą całkowitą:
żądanie 1 rozpoczęło się -> spinner włączony -> żądanie 2 się zaczęło -> żądanie 1 się kończyło -> żądanie 2 się kończyło -> spinner wyłączony
źródło
isFetching
flagą. Jeśli przyjrzysz się uważnie przykładowi, z którym się połączyłem, zobaczysz, że nie ma jednego obiektu zisFetched
wieloma: jeden na subreddit (co jest właśnie pobierane w tym przykładzie).fetchCounter
pasek postępu u góry ekranu, jak i kilka konkretnychisFetching
flag dla list i stron.Chciałbym coś dodać. Przykład ze świata rzeczywistego używa pola
isFetching
w sklepie do reprezentowania czasu pobierania kolekcji elementów. Każda kolekcja jest uogólniana napagination
reduktor, który można połączyć z komponentami w celu śledzenia stanu i pokazania, czy kolekcja jest ładowana.Zdarzyło mi się, że chciałem pobrać szczegóły dotyczące konkretnego podmiotu, który nie mieści się we wzorcu paginacji. Chciałem mieć stan reprezentujący, czy szczegóły są pobierane z serwera, ale także nie chciałem mieć reduktora tylko do tego.
Aby rozwiązać ten problem, dodałem inny ogólny reduktor o nazwie
fetching
. Działa podobnie jak reduktor paginacji i jego zadaniem jest po prostu obserwowanie zestawu działań i generowanie nowego stanu parami[entity, isFetching]
. Pozwala toconnect
na redukcję do dowolnego komponentu i sprawdzenie, czy aplikacja aktualnie pobiera dane nie tylko dla kolekcji, ale dla określonej jednostki.źródło
Do tej pory nie spotkałem się z tym pytaniem, ale ponieważ żadna odpowiedź nie zostanie przyjęta, wrzucę kapelusz. Napisałem narzędzie do tego właśnie zadania: reaktor-loader-fabryka . Trochę więcej się dzieje niż rozwiązanie Abramova, ale jest bardziej modułowe i wygodne, ponieważ nie chciałem myśleć po tym, jak to napisałem.
Istnieją cztery duże elementy:
const loaderWrapper = loaderFactory(actionsList, monitoredStates);
connect()
powraca w Redux), więc możesz go po prostu przykręcić do istniejących rzeczy.const LoadingChild = loaderWrapper(ChildComponent);
ACTION_SUCCESS
iACTION_REQUEST
). (Oczywiście, jeśli chcesz, możesz wysłać akcje w inne miejsce i po prostu monitorować z opakowania).Sam moduł jest niezależny od oprogramowania pośredniczącego redux-api, ale właśnie z tym go używam, więc oto przykładowy kod z pliku README:
Komponent z opakowaniem Loadera:
Reduktor do monitorowania przez Loader (chociaż możesz go podłączyć inaczej, jeśli chcesz):
Spodziewam się, że w najbliższej przyszłości dodam do modułu takie rzeczy, jak przekroczenie limitu czasu i błąd, ale wzorzec nie będzie się bardzo różnił.
Krótka odpowiedź na Twoje pytanie brzmi:
źródło
Czy tylko ja myślę, że wskaźniki ładowania nie powinny być dostępne w sklepie Redux? Chodzi mi o to, że nie sądzę, że jest to część stanu aplikacji jako takiej ...
Teraz pracuję z Angular2 i to, co robię, to to, że mam usługę "Loading", która pokazuje różne wskaźniki ładowania za pośrednictwem RxJS BehaviourSubjects .. Myślę, że mechanizm jest taki sam, po prostu nie przechowuję informacji w Redux.
Użytkownicy usługi LoadingService po prostu subskrybują te zdarzenia, których chcą słuchać.
Twórcy moich akcji Redux wywołują usługę LoadingService, gdy tylko coś się zmieni. Komponenty UX subskrybują ujawnione obserwable ...
źródło
Możesz dodać odbiorników zmian do swoich sklepów, korzystając
connect()
z React Redux lub metody niskiego poziomustore.subscribe()
. Powinieneś mieć wskaźnik ładowania w swoim sklepie, który program obsługi zmian sklepu może następnie sprawdzić i zaktualizować stan komponentu. Następnie komponent renderuje moduł wstępnego ładowania, jeśli to konieczne, na podstawie stanu.alert
iconfirm
nie powinno stanowić problemu. Blokują, a alarmy nie wymagają nawet żadnych danych wejściowych od użytkownika. Za pomocąconfirm
można ustawić stan na podstawie tego, co kliknął użytkownik, jeśli wybór użytkownika powinien wpłynąć na renderowanie komponentu. Jeśli nie, możesz zapisać wybór jako zmienną składową komponentu do późniejszego wykorzystania.źródło
addNofication(message)
. Innym przypadkiem są preloadery, które są również dostarczane przez natywną aplikację hosta i wyzwalane przez jej interfejs API JavaScript. Dodaję opakowanie dla tych interfejsów API wcomponentDidUpdate
komponencie React. Jak zaprojektować rekwizyty lub stan tego komponentu?W naszej aplikacji mamy trzy rodzaje powiadomień, z których wszystkie są zaprojektowane jako aspekty:
Wszystkie trzy z nich znajdują się na najwyższym poziomie naszej aplikacji (Main) i są połączone przez Redux, jak pokazano na poniższym fragmencie kodu. Te rekwizyty kontrolują wyświetlanie odpowiadających im aspektów.
Zaprojektowałem proxy, które obsługuje wszystkie nasze wywołania API, dlatego wszystkie błędy isFetching i (api) są zapośredniczone przez actionCreators, które importuję w proxy. (Nawiasem mówiąc, używam również pakietu webpack do wstrzyknięcia makiety usługi tworzenia kopii zapasowych dla programistów, abyśmy mogli pracować bez zależności od serwera).
Każde inne miejsce w aplikacji, które wymaga podania dowolnego rodzaju powiadomienia, po prostu importuje odpowiednią akcję. Snackbar i Error mają parametry wyświetlania komunikatów.
) eksportuje domyślną klasę Main rozszerza React.Component {
źródło
Zapisuję adresy URL takie jak:
A potem mam zapamiętany selektor (przez reselect).
Aby adres URL był unikalny w przypadku POST, przekazuję jakąś zmienną jako zapytanie.
A gdzie chcę pokazać wskaźnik, po prostu używam zmiennej getFetchCount
źródło
Object.keys(items).filter(item => items[item] === true).length > 0 ? true : false
przezObject.keys(items).every(item => items[item])
drodze.some
zamiastevery
, ale tak, zbyt wiele niepotrzebnych porównań w pierwszym zaproponowanym rozwiązaniu.Object.entries(items).some(([url, fetching]) => fetching);