brianegan / flutter_redux

A library that connects Widgets to a Redux Store
MIT License
1.65k stars 217 forks source link

Question on how to use the reducer right way #240

Open Lyba97 opened 2 years ago

Lyba97 commented 2 years ago

I am working on redux for state management and using MVVM architecture. 

I have made a generic reducer that only returns the updated store. For each feature I make a class, let’s call it a sub-store, and make this class in AppStore as a data member to maintain its own state. Now for each sub-store, I made a reducer that extends the generic reducer for common operations. My generic reducer takes the old sub-store and takes the new sub-store as action and depending on the API state e.g. (‘isLoading’, ’success’), updates the store. Since reducers are supposed to have logic. I am processing and calculating the new sub-store state either in thunkAction or in ViewModel and dispatching the Action only when the new sub-store is ready to be updated. Let's say I want to update the data member isNewUser. I will do this in ThunkAction:


UserLoginStore loginStore = store.state.userLoginStore.copyWith(isNewUser: true);
store.dispatch(ApiResponseAction<UserLoginStore>(apiResState: ApiResState.success, updateStore: loginStore));



Am I doing it right? In this way, the reducer does not have much logic despite some specific functionalities that may be required by a specific sub-store. 
 As it can be seen in the above snippet I created an instance of UserLoginStore and kept the updated store in that and then dispatched the action to the reducer where the actual state will be updated for the application.

// sub-store
class 
UserLoginStore {
  final UserModel userModel;
  final bool isNewUser;
  final ApiResState apiResState;
}

//main store
class AppStore {
  final QueriesStore queriesStore;
  final UserLoginStore userLoginStore;
  final UserExistsModel userExistsStore;
}

//generic Action 
class ApiResponseAction<T> {
  ApiResState apiResState;
  T? updateStore; //only populated if response is a success

  ApiResponseAction({required this.apiResState, this.updateStore});
}

// generic reducer
abstract class AppStateReducer<T> {
  T apiResponse(state, ApiResponseAction<T> action) {
    switch (action.apiResState) {
        case ApiResState.isLoading:
        return state!.copyWith(apiResState: action.apiResState);

      case ApiResState.success:
        return action.updateStore == null
            ? state.copyWith(apiResState: action.apiResState)
            : action.updateStore;
    }
  }

  Reducer<T> get apiResponseReducer => combineReducers<T>([
        TypedReducer<T, ApiResponseAction<T>>(apiResponse),
      ]);
}
Lyba97 commented 2 years ago

@brianegan

Lyba97 commented 2 years ago

hi @brianegan. Did you get a chance to review this, please? It would be great if you could check it will help me a lot these days.