简体   繁体   中英

Flutter reuse state from StatefulWidget on rebuild

In short, the question is: How do I reuse the state of an entire widget subtree?


This is what my code currently looks like:

...
BlocBuilder<AuthBloc, AuthState>(
  builder: (context, state) {
    if (state is Authenticating) {
      return AppLoading();
    } else if (state is NotAuthenticated) {
      return AppOnboarding();
    } else if (state is Authenticated) {
      return AppMain();
    } else {
      return null;
    }
  }
),
...

Nothing fancy here, just a BlocBuilder rebuilding its child whenever the state of the underlying Bloc changes.

Now, take for instance the following state transitions: NotAuthenticated => Authenticating => NotAuthenticated because there was something wrong with the inputed information. This would result in the AppOnboarding() widget being rebuild completely from scratch with all the information lost. How can I reuse the state from the old AppOnboarding() widget to make it look like the widget was never rebuild?


What I've already tried

I've already tried using a GlobalKey for this which I would pass to the key property of my AppOnboarding widget. This is my code:

_AuthenticatingState extends State<Authenticating> {
  GlobalKey<AppOnboardingState> _appOnboardingKey;

  @override
  initState() {
    super.initState();
    _appOnboardingKey = GlobalKey();
  }

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<...>(
      builder: (context, state) {
        ...
        if (state is NotAuthenticated) {
          return AppOnboarding(key: _appOnboardingKey);
        }
        ...
      }
    ),
  }
}

I was a little surprised this didn't work. Do global keys not maintain the state of the entrie widget-subtree?

Flutter runs at 60 frames per second. The key tells Flutter that some widget is the same one that existed in the last frame. If you remove some widget, even for a single frame, it will dispose the widget (call the dispose method and get rid of the widget).

In other words, the key doesn't "save" any state for later.

You have two options:

  1. Don't dispose the widget at all.
builder: (context, state) {
    return Stack(children: [
    Offstage(child:AppLoading(), offstage: state is! Authenticating),
    Offstage(child:AppOnboarding()), offstage: state is! NotAuthenticated),
    Offstage(child:AppMain()), offstage: state is! Authenticated),
    ]) }
  }
  1. Save yourself that widget state, so that you can rebuild the widget later with that same information.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM