Skip to content
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

Widget not rebuilding #77

Closed
arthurgustin opened this issue Sep 3, 2018 · 7 comments
Closed

Widget not rebuilding #77

arthurgustin opened this issue Sep 3, 2018 · 7 comments

Comments

@arthurgustin
Copy link

Hi, I'm in a situation where I want to globally disable user input on certain events. For this I have created 2 actions, Lock() and Unlock() that I dispatch before and after another action, like this:

    return new StoreConnector<AppState, TeacherViewModel>(
        converter: (store) {
          [...]

          return TeacherViewModel(
              buttonPressed: buttonPressed,
              loading: store.state.disableUserInputAndShowLoadingAnimation,
              onSave: () {
                store.dispatch(new Lock());
                store.dispatch(new ApiSaveKidAction(onSuccess: (String message){
                  Keys.scaffoldState.currentState.showSnackBar(MySnack.success(message));
                },onError: (String message) {
                  Keys.scaffoldState.currentState.showSnackBar(MySnack.error(message));
                }));
                store.dispatch(new Unlock());
              },
          );
        },
        builder: (BuildContext context, TeacherViewModel vm) {
          if (vm.loading) {
            return MyButton.load();
          } else {
            return MyButton.dark("Save", () {
              vm.onSave();
            }, pressed: vm.buttonPressed);
          }
        }
    );

And in a top-level widget I have this kind of code:

if (vm.disableUserInputAndShowLoadingAnimation) {
  stack = new Stack(
      fit: StackFit.expand,
      children: [
        roleBasedHomeWidget,
        new LoadAndDisableUserInteraction()
      ]);
}

return MaterialApp(
    home: stack,
);

The stacks put my loading animation on top of the real app.

And I have the feeling my widgets are not rebuilding untill the end of the function onSave()

In my understanding, each trigerred actions would go through reducers, then middlewares, then the app rebuilds, so with my function onSave(), this workflow would execute 3 times right ?
But fact is this does not work, I obviously missed something, but what... ?

@brianegan
Copy link
Owner

brianegan commented Sep 3, 2018

Yah, this can be a tricky one!

In my understanding, each trigerred actions would go through reducers, then middlewares, then the app rebuilds, so with my function onSave(), this workflow would execute 3 times right ?

In this case, the Redux part is synchronous and will inform Widget's that the state has changed -- but Flutter rebuilds Widgets on it's own schedule, generally after the current synchronous calls have executed.

In your example, you're synchronously Locking, Doing some work, then Unlocking. Even if Flutter were fully synchronous itself, this would at best make the button Flash locked, then almost immediately go back to unlocked since you're performing these tasks one after the other.

When do you want to Unlock the button? As a result of a Failure? Or after the ApiSavedKitAction has completed?

@arthurgustin
Copy link
Author

@brianegan thx for your fast answer ! I want to unlock both on failure and on success

@brianegan
Copy link
Owner

Makes sense -- in that case, you need to move the store.dispatch(new Unlock()); call inside the Success / Error functions, or add another callback called onComplete to the ApiSaveKidAction that should be invoked after either success or failure.

That way, your Async work will complete, then Unlock will be called.

@arthurgustin
Copy link
Author

Alright, I will try that when I get home, same for Lock() ?

@brianegan
Copy link
Owner

brianegan commented Sep 3, 2018

Nope! It sounds like you want the following Flow:

  1. Lock immediately to prevent more button taps
  2. Perform some work
  3. When the work is complete, Unlock the button

Therefore, you want to dispatch Lock immediately (synchronously), and dispatch Unlock when the Work is complete (asynchronously).

@arthurgustin
Copy link
Author

Oh I get it now ! If I don't come back on this thread it means that you solved my problem, thx !

@brianegan
Copy link
Owner

@arthurgustin Sure thing! Good luck :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants