Combine reducers in Flutter
The action that you dispatch will be sent to all the reducers. Using checks you can mutate your state easily. This will also prevent unnecessary updates in the state.
Very soon you will have multiple actions being dispatched & handling them as follows will allow you to do that.
Your signUpReducer
should look something like this:
signUpReducer(SignUpState prevState, dynamic action) {
if (action is SetSignUpStateAction) {
return setSignUpState(prevState, action);
}
return prevState;
}
SignUpState setSignUpState(SignUpState prevState, SetSignUpStateAction action) {
final payload = action.signUpState;
print(action); // prints Instance of 'SetSignUpStateAction'
print(prevState); // prints Instance of 'SignUpState'
print("signUpReducer");
return prevState.copyWith(
isError: payload.isError,
isLoading: payload.isLoading,
isLoggedIn: payload.isLoggedIn,
);
}
Your loginReducer
should look something like this:
loginReducer(LoginState prevState, dynamic action) {
if(action is SetLoginStateAction) {
return setLoginState(prevState, action);
}
return prevState;
}
LoginState setLoginState(LoginState prevState, SetLoginStateAction action) {
final payload = action.loginState;
return prevState.copyWith(
isError: payload.isError,
isLoading: payload.isLoading,
);
}
user3808307
Updated on December 01, 2022Comments
-
user3808307 over 1 year
I am using Redux with Flutter with this library. If the solution is to change to redux dart library then I will change it.
This is the code I have for the store, I have been taking parts from different tutorials
@immutable class AppState { final SignUpState signUpState; final LoginState loginState; AppState({ @required this.signUpState, @required this.loginState, }); AppState copyWith({ SignUpState signUpState, LoginState loginState, }) { return AppState( signUpState: signUpState ?? this.signUpState, loginState: loginState ?? this.loginState, ); } } AppState appReducer(AppState state, action) { return AppState( signUpState: signUpReducer(state.signUpState, action), // loginState: loginReducer(state.loginState, action), ); } class Redux { static Store<AppState> _store; static Store<AppState> get store { if (_store == null) { throw Exception("store is not initialized"); } else { return _store; } } static Future<void> init() async { final signUpStateInitial = SignUpState.initial(); final loginStateInitial = LoginState.initial(); _store = Store<AppState>( appReducer, middleware: [thunkMiddleware, new LoggingMiddleware.printer()], initialState: AppState( signUpState: signUpStateInitial, loginState: loginStateInitial, ), ); } }
I am testing first with signUpState, which currently works when I only use that one, the moment I add another reducer and uncomment the line
// loginState: loginReducer(state.loginState, action),
on trying to dispatch a signUp related Action that does work with the above line commented I get
Uncaught (in promise) Error: Expected a value of type 'SetLoginStateAction', but got one of type 'SetSignUpStateAction'
I thought this part of the code was combining the reducers:
AppState appReducer(AppState state, action) { return AppState( signUpState: signUpReducer(state.signUpState, action), loginState: loginReducer(state.loginState, action), ); }
How would I do it then?
Edit: I changed the code like this now, but still problem persists
@immutable // Define your State class AppState { final SignUpState signUpState; final LoginState loginState; AppState(this.signUpState, this.loginState); } AppState appReducer(AppState state, action) => new AppState( signUpReducer(state.signUpState, action), loginReducer(state.loginState, action), ); class Redux { static Store<AppState> _store; static Store<AppState> get store { if (_store == null) { throw Exception("store is not initialized"); } else { return _store; } } static Future<void> init() async { // print(1); final signUpStateInitial = SignUpState.initial(); // print(2); final loginStateInitial = LoginState.initial(); // print(3); _store = Store<AppState>( appReducer, middleware: [thunkMiddleware, new LoggingMiddleware.printer()], initialState: AppState( signUpStateInitial, loginStateInitial, ), ); } }
Edit: this is the signup state (it does not do much since I was only testing)
@immutable class SignUpState { final bool isError; final bool isLoading; final bool isLoggedIn; SignUpState({ this.isError, this.isLoading, this.isLoggedIn, }); factory SignUpState.initial() => SignUpState( isLoading: false, isError: false, isLoggedIn: false, ); SignUpState copyWith({ @required bool isError, @required bool isLoading, @required bool isLoggedIn, }) { return SignUpState ( isError: isError ?? this.isError, isLoading: isLoading ?? this.isLoading, isLoggedIn: isLoggedIn ?? this.isLoading, ); } }
And the signup reducer
signUpReducer(SignUpState prevState, SetSignUpStateAction action) { final payload = action.signUpState; print(action); // prints Instance of 'SetSignUpStateAction' print(prevState); // prints Instance of 'SignUpState' print("signUpReducer"); return prevState.copyWith( isError: payload.isError, isLoading: payload.isLoading, isLoggedIn: payload.isLoggedIn, ); }
The print statement executes
Edit 2:
This is the login reducer, but nothing is going through here yet, I don't have any login actions implemented
loginReducer(LoginState prevState, SetLoginStateAction action) { final payload = action.loginState; return prevState.copyWith( isError: payload.isError, isLoading: payload.isLoading, ); }
-
Rahul Sharma over 3 yearsYou have
this.loginState
defined as@required
but you are not sending it. I think you might want to solve it. -
Ravi Singh Lodhi over 3 yearsPlease show your redux actions also. How are you dispatching & handling them? There might be some issues while managing the actions.
-
user3808307 over 3 years@RaviSinghLodhi I added the initial state and reducer for signup, it goes through the reducer, the problem is when coming out
-
user3808307 over 3 yearsI think I am going to start over
-
Ravi Singh Lodhi over 3 yearsPlease show
loginReducer
as well. I think you should usedynamic
instead ofSetSignUpStateAction
. Multiple actions will be dispatched from your state. Hence, you should usedynamic
. Also, you will have to useif-else
conditions to manage the actions. -
Ravi Singh Lodhi over 3 yearsI too had to take multiple snippets from tutorials, blogs, youtube videos etc. Don't worry. I will help you.
-
user3808307 over 3 years@RaviSinghLodhi I added it but I think it makes no difference, as I am not dispatching any login actions for now. I will start over today with a different tutorial. If there is one to recommed...
-
Ravi Singh Lodhi over 3 yearsWhen you uncomment your
loginReducer
& if you dispatch a signup action, it will go to bothsignUpReducer
as well asloginReducer
. This will be causing the issue. Just add some checks. I am writing an answer & will update if necessary.
-