skip to Main Content

I am facing the following problem:

I have a StatefulWidget which can generate different view in case of state change:

class _HomePageState extends State<HomePage> {
  bool _changed = false;

  @override
  Widget build(BuildContext context) {
    return changed ? View2() : View1();
  }
}

If I change a state _changed to true and hit the back button, a then the forward button, I would like my application to create fresh _HomePageState and display a View1, but currently the View2 is presented, so I believe that the state is persisted somehow.

How can I force rebuild of the widget’s state?

Example app presenting the problem: link

Steps to reproduce:

  1. Open some site, eg. www.google.com
  2. Paste the link to the app https://issueapp.tiiny.site
  3. Change the state of the app by pressing a button
  4. Press browser’s back button
  5. Press browser’s forward button

GIF presenting the issue:

enter image description here

2

Answers


  1. This only happen on release version of flutter web. Your flutter web state will be keep in navigation stack, until you do a page refresh.

    Here some additional comment from flutter web issue related to Refreshing browser resets navigation stack and local variables :

    When you refresh the page, the entire app is destroyed and launched again. This is how the browser works, nothing specific to Flutter here. So the values of local variables are expected to disappear.

    The way navigation works today is by keeping the navigation stack in memory. This means the stack is destroyed on page refresh, and the history is lost.

    Read the github complete comment here by mdebbar

    Login or Signup to reply.
  2. There are a couple of ways to do that, the easiest way now is just adding a wrapper as a parent widget, that receives a callback when you press the back button from your browser, and then restart the widget.

    Results:

    enter image description here

    Code:

    • You need to call MyParentWidget first.
    • You can use any widget to refresh the key, I’m just using setState for simplicity.
    class MyParentWidget extends StatefulWidget {
      const MyParentWidget({
        super.key,
      });
    
      @override
      State<MyParentWidget> createState() => _MyParentWidgetState();
    }
    
    class _MyParentWidgetState extends State<MyParentWidget> {
      @override
      Widget build(BuildContext context) {
        return MyHomePage(
          key: UniqueKey(),
          onBackPressed: () {
            setState(() {});
          },
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({
        required this.onBackPressed,
        super.key,
      });
    
      final VoidCallback onBackPressed;
    
      @override
      State<MyHomePage> createState() {
        return _MyHomePageState();
      }
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      bool _changed = false;
    
      @override
      Widget build(BuildContext context) {
        return WillPopScope(
          onWillPop: () => Future(() {
            widget.onBackPressed();
            return false;
          }),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Text(
                _textForCurrentState(),
                style: const TextStyle(
                  color: Colors.black,
                  decoration: TextDecoration.none,
                ),
              ),
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    _changed = !_changed;
                  });
                },
                child: const Text("CHANGE"),
              ),
            ],
          ),
        );
      }
    
      String _textForCurrentState() {
        return _changed ? "CHANGED" : "NOT CHANGED";
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search