IndexedStack widgets are not updating
Asked Answered
C

3

6

I am using IndexedStack widget and providing the list of widgets based on some logic. I have a list page that shows pupil's list and another page to add new pupil.

When I add new pupil, it add successfully and stored in firestore. But when I switch back to pupil's listing page it doesn't show the newly added pupil. It show's all other pupil's except the last created one. If I close the app and open again then it shows all pupils including the added one.

I put some log and found out that, widgets build function get called very first time of the application load. Next time widgets are loading from cache I guess because build function doesn't get called.

Do I need to reload the pupil listing widget every time manually? Is there a way to do that? Or there are some other way to tell IndexedStack widget to reload the widget every time. How can I get the newly added pupil in listing page without restarting the app?

IndexedStack code:

body: Center(
    child: IndexedStack(
      index: _selectedPage,
      children: this._widgets,
    ),
  )

Pupil listing page code:

@override
Widget build(BuildContext context) {
Logger _logger = Logger(this.runtimeType.toString());
_logger.fine('Loading pupils listing page.');
return StreamBuilder<QuerySnapshot>(
  stream: _querySnapshot,
  builder: (BuildContext context, 
AsyncSnapshot<QuerySnapshot>        snapshot) {
    if (snapshot.data == null) 
return   FrequentWidgets().getProgressBar();
    if (snapshot.hasError) return Text('Error: ${snapshot.error}');
    switch (snapshot.connectionState) {
      case ConnectionState.waiting:
        return Text('Loading...');
      default:
        return ListView(
          children: snapshot.data.documents.map(
            (DocumentSnapshot document) {
              return ListTile(
                trailing: Icon(Icons.person),
                title: Text(document["nam"]),
                onTap: () {
                  appData.pupilId = document.documentID;
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => HomePage(
                        sectionType:  
 SectionType.InstructorActivityForPupil,
                        userType: UserType.Instructor,
                        contextInfo: {
                          DataSharingKeys.PupilIdKey: 
document.documentID
                        },
                      ),
                    ),
                  );
                },
              );
            },
          ).toList(),
        );
      }
   },
  );
}
Cerveny answered 29/8, 2019 at 18:34 Comment(0)
C
14

IndexedStack widgets' purpose is to show one widget at a time among multiple widgets. But, IndexedStack will build and load all the widgets passed to it during load. Then, The requested widget will be displayed from cache without actually building the widget. That's why build method of passed widget will get only once at the during app load. Subsequent request will be displayed from cache.

I have used TabBarView instead of IndexedStack widget. TabBarView has nearly same objective but supplied widgets will get called on every request.

Cerveny answered 24/10, 2019 at 6:27 Comment(0)
I
4

To understand the problem, you should learn about widget tree and and element tree first. For solution, this can be resolved by passing a new unique key into this widget whenever you want to refresh it with new list of items. IndexedStack( index: selectedIndex, children:list, key:ObjectKey(list[0].hashCode))

Immune answered 5/9, 2022 at 10:1 Comment(0)
C
0

Here is a workaround:-

Store the pages in a list

final List<Widget> _pages = [
    const PageA(),
    const PageB(), 
    const PageC(), 
    const PageD() 
  ];

IndexedStack(
              index: Provider.of<NavigationProvider>(context, listen: true).selectedIndex,
              children: Provider.of<NavigationProvider>(context, listen:true).pages,
            ),

Whenever you want to rebuild a page, remove it from the list and add it again.

// first remove the page from the List
_pages.removeAt(2);
// then add it again
_pages.insert(2, const PageC())

Since the pages doesn't have a static key it will try to rebuild the page.

If you want to give a key to the page or the widget, make it dynamic to work the above method.

eg: PageC(key: Key('PageC${DateTime.now().millisecondsSinceEpoch}'),)
Connection answered 5/4 at 6:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.