New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation as a result of action in redux/built_redux pattern #26

Closed
lwasyl opened this Issue Mar 6, 2018 · 8 comments

Comments

Projects
None yet
6 participants
@lwasyl

lwasyl commented Mar 6, 2018

Hi, I'm wondering how should I implement the case when the screen should change as a result of some action -- say to swap LoginPage to HomePage. Successful login would be an action, so I would either push route in middleware (I don't have the context, though) or somehow put the route in app state, but then I'd be just swapping widgets in store connection, not actually pushing new routes with the navigator.

Overall how should navigation triggered by the actions be handled (as opposed to navigation happening as a result of user interaction)?

@passsy

This comment has been minimized.

Contributor

passsy commented Mar 7, 2018

I agree. Navigating without changing the state seems wrong. But I'm not sure how a Route push/pop could be pushed from a state change.

@brianegan

This comment has been minimized.

Owner

brianegan commented Mar 7, 2018

I think the easiest way I've seen to do this is using Middleware. Middleware should perform side effects, and integrating with the Navigator feels like one of those side effects.

Probably the easiest way to achieve this is to set a navigatorKey on your material app, and use that Key to access the navigator in your middleware.

Example can be found here:

https://github.com/brianegan/flutter_redux/blob/simple-navigation-example/example/lib/main.dart#L20

Let me know if you have more thoughts / ideas on how to improve this!

@lwasyl

This comment has been minimized.

lwasyl commented Mar 12, 2018

I didn't think about keys to retrieve the navigator! I think this answers my question and makes sense, I'll do this at least for now, thanks :)

@lwasyl lwasyl closed this Mar 12, 2018

@xrigau

This comment has been minimized.

xrigau commented Mar 20, 2018

I've gone a different route (get it? 😅) to approaching this, and would appreciate to hear your thoughts @brianegan (and whoever wants to chime in, of course!)

Whenever I create a new page, in the build method I pass the Navigator to the ViewModel of that page:

class WelcomePage extends StatelessWidget {

  @override
  Widget build(BuildContext context) => StoreConnector<AppState, _ViewModel>(
      converter: (Store<AppState> store) => _ViewModel.create(store, LocalNavigator(Navigator.of(context))),
      builder: (context, viewModel) => Stack(
            children: FlatButton("Sign In", onPressed: viewModel.onSignIn),
          ));
}

Where LocalNavigator is just a thin layer on top of the Navigator:

class LocalNavigator {
  final NavigatorState _navigator;
  LocalNavigator(this._navigator);

  toSignIn() {
    _navigator.pushNamed(Routes.SignIn);
  }
}

Now what I'm not sure about is I have to pass the navigator to the Action and deal with it using Middleware:

@immutable
class _ViewModel {
  final Function onSignIn;
  _ViewModel({@required this.onSignIn});

  factory _ViewModel.create(Store<AppState> store, LocalNavigator navigator) => _ViewModel(
        onSignIn: () => store.dispatch(SignInAction(navigator))
      );
}
class SignInAction {
  final LocalNavigator navigator;
  SignInAction(this.navigator);
}
Middleware<AppState> _signInAction() {
  return (Store<AppState> store, action, NextDispatcher next) {
    if (action is SignInAction) {
      action.navigator.toSignIn();
    }
    next(action);
  };
}

This is the first time using Redux and I'm not too sure if this approach is in line with this architecture, what are your thoughts?

@brianegan

This comment has been minimized.

Owner

brianegan commented Mar 20, 2018

@xrigau That looks good to me! I think that's the best approach if you know you can navigate right in the view. It should definitely be done there.

I think the middleware approach makes more sense if you need to navigate based on some data-source action. For example, perhaps your phone receives a notification and you've got a middleware that dispatches a "new NotificationNavigationAction()`. In that case, you'd have to handle stuff in the Middleware.

@xrigau

This comment has been minimized.

xrigau commented Mar 20, 2018

Ah yeah that makes sense, so if it's not a user action then the Middleware approach would be the way to go, thanks! 👍

@techyrajeev

This comment has been minimized.

techyrajeev commented Jul 30, 2018

Middleware based approach would best suite for the use case where user needs to be force logged out incase of refreshToken expiration, If I am not wrong.

@rubensdemelo

This comment has been minimized.

rubensdemelo commented Oct 31, 2018

So, basically we have 2 approach to routes our app using redux:

In ViewModel, using sync actions.
In Middleware, when need an async operation.

Is that ok ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment