|
6 | 6 | <p align="center">
|
7 | 7 | <img src="https://github.com/hoc081098/rx_redux/blob/v2/images/logo.png?raw=true" alt="Logo" width="300"/>
|
8 | 8 | </p>
|
| 9 | + |
| 10 | +## Effects with RxDart |
| 11 | + |
| 12 | +```dart |
| 13 | +RxReduxStore<HomeAction, HomeState> createStore(SearchUseCase searchUseCase) => |
| 14 | + RxReduxStore( |
| 15 | + initialState: HomeState.initial(), |
| 16 | + sideEffects: HomeSideEffects(searchUseCase)(), |
| 17 | + reducer: (state, action) => action.reduce(state), |
| 18 | + logger: rxReduxDefaultLogger, |
| 19 | + ); |
| 20 | +
|
| 21 | +class HomeSideEffects { |
| 22 | + final SearchUseCase _searchUseCase; |
| 23 | +
|
| 24 | + HomeSideEffects(this._searchUseCase); |
| 25 | +
|
| 26 | + List<SideEffect<HomeAction, HomeState>> call() => [ |
| 27 | + searchActionToTextChangedAction, |
| 28 | + search, |
| 29 | + nextPage, |
| 30 | + retry, |
| 31 | + ]; |
| 32 | +
|
| 33 | + Stream<HomeAction> searchActionToTextChangedAction( |
| 34 | + Stream<HomeAction> actions, |
| 35 | + GetState<HomeState> getState, |
| 36 | + ) => |
| 37 | + actions |
| 38 | + .whereType<SearchAction>() |
| 39 | + .debounceTime(const Duration(milliseconds: 500)) |
| 40 | + .map((action) => action.term.trim()) |
| 41 | + .where((term) => term.isNotEmpty) |
| 42 | + .distinct() |
| 43 | + .map((term) => TextChangedAction((b) => b..term = term)); |
| 44 | +
|
| 45 | + Stream<HomeAction> search( |
| 46 | + Stream<HomeAction> actions, |
| 47 | + GetState<HomeState> getState, |
| 48 | + ) => |
| 49 | + actions |
| 50 | + .whereType<TextChangedAction>() |
| 51 | + .map((action) => action.term) |
| 52 | + .switchMap((term) => _nextPage(term, 1)); |
| 53 | +
|
| 54 | + Stream<HomeAction> nextPage( |
| 55 | + Stream<HomeAction> actions, |
| 56 | + GetState<HomeState> getState, |
| 57 | + ) { |
| 58 | + final textChangedAction$ = actions.whereType<TextChangedAction>().debug(); |
| 59 | +
|
| 60 | + final performLoadingNextPage = (LoadNextPageAction action) { |
| 61 | + return Stream.value(getState()) |
| 62 | + .where((state) => state.canLoadNextPage) |
| 63 | + .exhaustMap((state) => _nextPage(state.term, state.page + 1) |
| 64 | + .takeUntil(textChangedAction$) |
| 65 | + .debug()); |
| 66 | + }; |
| 67 | +
|
| 68 | + return actions |
| 69 | + .whereType<LoadNextPageAction>() |
| 70 | + .exhaustMap(performLoadingNextPage); |
| 71 | + } |
| 72 | +
|
| 73 | + Stream<HomeAction> retry( |
| 74 | + Stream<HomeAction> actions, |
| 75 | + GetState<HomeState> getState, |
| 76 | + ) { |
| 77 | + final textChangedAction$ = actions.whereType<TextChangedAction>().debug(); |
| 78 | +
|
| 79 | + final performRetry = (RetryAction action) { |
| 80 | + return Stream.value(getState()) |
| 81 | + .where((state) => state.canRetry) |
| 82 | + .exhaustMap((state) => _nextPage(state.term, state.page + 1) |
| 83 | + .takeUntil(textChangedAction$) |
| 84 | + .debug()); |
| 85 | + }; |
| 86 | +
|
| 87 | + return actions.whereType<RetryAction>().exhaustMap(performRetry); |
| 88 | + } |
| 89 | +
|
| 90 | + Stream<HomeAction> _nextPage(String term, int nextPage) { |
| 91 | + final loadingAction = SearchLoadingAction((b) => b |
| 92 | + ..term = term |
| 93 | + ..nextPage = nextPage); |
| 94 | +
|
| 95 | + return Rx.fromCallable(() => _searchUseCase(term: term, page: nextPage)) |
| 96 | + .map<HomeAction>( |
| 97 | + (items) => SearchSuccessAction((b) => b |
| 98 | + ..term = term |
| 99 | + ..items.replace(items)), |
| 100 | + ) |
| 101 | + .startWith(loadingAction) |
| 102 | + .onErrorReturnWith( |
| 103 | + (error) => SearchFailureAction((b) => b |
| 104 | + ..error = error |
| 105 | + ..term = term), |
| 106 | + ); |
| 107 | + } |
| 108 | +} |
| 109 | +``` |
0 commit comments