Flutter all widgets in drawer navigation get mounted on startup

Viewed 16

It seems that all the Widgets in the DrawerNavigation seem to be mounted on start-up, this includes any child widgets too. dispose seems to be called only when restarting the app. I am assuming this is NOT the intended lifecycle of widgets. I would expect each Widget(Screen) to be mounted when navigating to it and unmounted when navigating away.

This is my HomeScreen where navigation is handled:

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  //! Default to tribe overview screen - 1 -, 0 is mail screen
  int _drawerNavIndex = 1;

  /// [setSelectedTab] will update the current screen based on the tapped option
  /// from [DrawerContentWidget]
  void setSelectedTab(index) {
    // if the [_drawerNavIndex] is not the same as [index] update it to [index]
    // value
    if (_drawerNavIndex != index) {
      setState(() {
        _drawerNavIndex = index;
      });
    }
  }

  /// [selectedTabContent] will return the screen selected from the
  /// [DrawerContentWidget] based on [_drawerNavIndex]
  Widget selectedTabContent() {
    List<Widget> pages = [
      // Tribe Screens
      const TribeMailScreen(),
      const TribeHomeScreen(),
      const TribeAdvisorScreen(),
      const ConstructionScreen()

      // Alliance
    ];
    return IndexedStack(
      index: _drawerNavIndex,
      children: pages,
    );
  }

  @override
  Widget build(BuildContext context) {
    TribeSummary tribe = Provider.of<TribeSummary>(context, listen: true);

    // If the tribe uid value is `placeHolderTribe` assume that there is no
    // existing or active tribe for this account
    if (tribe.uid == 'placeHolderTribe') {
      return Scaffold(
        /// TODO: create a proper drawer or appBar for the [StartTribeWidget]
        appBar: AppBar(
          title: const Text('A flutter app'),
        ),
        body: const StartTribeWidget(),
      );

      // If the tribe `uid` value is `placeHolderTribe` assume that an error
      // occurred while trying to get the tribe stream or while the tribe stream
      // is parsed to [TribeSummary], log should give more information
    } else if (tribe.uid == 'placeHolderErrorTribe') {
      // TODO: create a bettter error screen for this situation
      return const Center(
        child: Text('Unable to retrieve tribe data'),
      );
    }

    // This Scaffold wraps the entire app, anything here will be avilable
    // globally
    return Scaffold(
      // App Bar
      appBar: const AppBarContent(),

      // [DrawerContentWidget] holds all the drawer content, it requires
      // [setSelectedTab] function to handle the navigation between screens and
      // [selectedTabIndex] to highlight the selected tab
      drawer: DrawerContentWidget(
        setSelectedTab: setSelectedTab,
        selectedTabIndex: _drawerNavIndex,
      ),

      // Display the contents of the selected screen
      body: selectedTabContent(),

      // Reserved
      bottomNavigationBar: SizedBox(
          height: 50,
          child: Container(
            color: Colors.red[100],
            child: const Center(child: Text('Reserved space')),
          )),
    );
  }
}
1 Answers

If you want each Screen to be mounted when navigating to it and unmounted when navigating away. You must use Navigator to navigate between your screens.

As on this answer https://stackoverflow.com/a/65863623/14952004

Regarding a page, the dispose method is called when the page is removed from the navigation stack. Here is a good explanation of Navigation.

That means you must use:

Navigator.push(...) to navigate new page without losing previous page.

Navigator.pushReplacement(...) to navigate new page and replace it with the previous page.

Navigator.pop(...) to dispose current page.

Related