redux_saga Put doesn't update the state in flutter

32 Views Asked by At

I'm using redux and redux_sage work for my flutter app.

my_store.dart

Store<AppState> myStore() {
  var sagaMiddleware = createSagaMiddleware();

  AppState appReducer(AppState state, action) {
    return AppState(
      user: userReducer(state.user, action),
    );
  }

  final store = Store<AppState>(
    appReducer,
    initialState: AppState.initial(),
    middleware: [applyMiddleware(sagaMiddleware)],
  );

  sagaMiddleware.setStore(store);
  sagaMiddleware.run(rootSaga);
  return store;
}

saga.dart

...

login({action}) sync* {
  var user = Result<User>();
  yield Call(loginAPI, args: [action.auth], result: user);
  yield Put(LoginSuccessAction(user.value!));
}

watchSaga() sync* {
  yield TakeLatest(login, pattern: LoginAction);
  //yield TakeEvery(fetchUser, pattern: FetchUserAction);
}

rootSaga() sync* {
  yield All({
    #t1: Fork(watchSaga),
  });
}

action.dart

class LoginAction {
  Auth auth;
  LoginAction(this.auth);
}

class LoginSuccessAction {
  User user;
  LoginSuccessAction(this.user);
}

reducers/user.dart

final userReducer = combineReducers<User>([
  TypedReducer<User, FetchUserAction>(fetchUserReducer),
  TypedReducer<User, LoginSuccessAction>(loginSuccessReducer),
]);

User fetchUserReducer(User state, FetchUserAction action) {
  return state.copyWith(fullname: state.fullname);
}

User loginSuccessReducer(User state, LoginSuccessAction action) {
  //here can get the user data, but doesn't update later.
  return action.user;
}

main.dart

void main() async {
  runApp(MainApp(store: myStore()));
}

class MainApp extends StatelessWidget {
  final Store<AppState> store;
  const MainApp({super.key, required this.store});
  @override
  Widget build(BuildContext context) {
    final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
    return StoreProvider<AppState>(
      store: store,
      child: MaterialApp(
        title: 'Provider Demo',
        navigatorKey: navigatorKey,
        onGenerateRoute: (RouteSettings settings) {
          final Map<String, WidgetBuilder> routes = {
            '/': (context) => const HomePage(),
            '/login': (context) => const Login(),
          };
          WidgetBuilder builder;
          if (settings.name == '/login') {
            builder = (context) => const Login();
          } else {
            User user = store.state.user;
            debugPrint(user.toString());//when login, still get the old state
            if (user.username == '') {
              builder = (context) => const Login();
            } else {
              builder = routes[settings.name!] ?? (context) => const NotFound();
            }
          }
          return MaterialPageRoute(builder: builder, settings: settings);
        },
      ),
    );
  }
}

login.dart has a login button to dispatch LoginAction

onPressed: () async {
  Auth auth = Auth(
    username: _username,
    password: _password,
  );
  await store.dispatch(LoginAction(auth));
  Navigator.pushNamed(context, '/');
},

in saga.dart, Call(loginAPI, args: [action.auth], result: user) has returned the right data, but Put method doesn't work, it doesn't update the state, so I still get the old state. anything wrong?

last update: this bug is caused by async call, if I change the onPress code to:

onPressed: () async {
  Auth auth = Auth(
    username: _username,
    password: _password,
  );
  await store.dispatch(LoginAction(auth));
  await Future<void>.delayed(const Duration(seconds: 1));
  Navigator.pushNamed(context, '/');
},

it works, so how to fix it?

0

There are 0 best solutions below