Multiple instances of same Statefulwidget seem to share the same State object?
Asked Answered
V

1

6

I'm trying to build an app using Flutter and am running into a small problem. I'm trying to implement a BottomNavigaionBar style app with three pages. (see first snippet) The layout makes use of three objects of type "ChorePage". It seems like the app is creating three instances of ChorePage, but only one instance of _ChorePageState.

This causes the variable _dataRows to be shared between the three tabs meaning I can't put different information into the different tabs. Why is this happening and how do I prevent it?

I have put print statements into the createState() function and am printing the 'this' variable in the PopulateRows function which is called on every rebuild of the ChorePage. The print output is seen below and confirms that indeed the three widgets use the same State object. (createState is only called once for object A and the this variable refers to the same object)

class AppLayout extends StatefulWidget {
  @override
  _AppLayoutState createState() => _AppLayoutState();
}

class _AppLayoutState extends State<AppLayout> {
  int _currentIndex = 0;
  String title = 'Test';

  List<Widget> _children = [
    new ChorePage(Title:'A'),
    new ChorePage(Title:'B'),
    new ChorePage(Title:'C')
  ];

  @override
  Widget build(BuildContext context) {


    //STUFF BEFORE INIT
    return Scaffold(
      appBar: AppBar(
        title: Text('$title'),
      ),
      body: _children[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        onTap: onTabTapped,
        currentIndex: _currentIndex,
        items:[
          BottomNavigationBarItem(
            icon: Icon(MdiIcons.sprayBottle),
            title:Text('Menu1'),
          ),
          BottomNavigationBarItem(
            icon: Icon(MdiIcons.glassMugVariant),
            title:Text('Menu2'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.event_note),
            title:Text('Menu3'),
          )
      ]
      ),
    );
  }

  void onTabTapped(int index){
    setState(() {
      _currentIndex = index;
    });
  }
}

ChorePage


class ChorePage extends StatefulWidget {
  final String Title;
  const ChorePage({Key key, this.Title}): super(key: key);

  @override
  _ChorePageState createState() {
    print('Creating: '+this.Title);
    return new _ChorePageState();
  }
}

class _ChorePageState extends State<ChorePage> {
  List<DataRow> _dataRows = [];

  @override
  Widget build(BuildContext context) {
    PopulateRows();
    return SingleChildScrollView(
      child:Center(
          child: DataTable(
            columns: [
              DataColumn(label: Text(widget.Title.toString())),
              DataColumn(label: Text('Col1')),
              DataColumn(label: Text('Col2')),
            ],
            rows: _dataRows,
          ),
        ),
    );
  }

  void PopulateRows(){
    print(this);
    print(widget.Title.toString());

    //_dataRows = [];
    for(int i=0;i<1;i++) {
      DataRow R = DataRow(cells:[]);
      R.cells.add(DataCell(Text(widget.Title)));
      R.cells.add(DataCell(Text(i.toString())));
      R.cells.add(DataCell(Text((i + 1).toString())));
      _dataRows.add(R);
    }
  }

}

Print Output:

Installing build\app\outputs\apk\app.apk...
Debug service listening on ws://127.0.0.1:59033/TvJtQ-PN3a8=/ws
Syncing files to device Mi 9T Pro...
I/flutter (28856): Creating: A
I/flutter (28856): _ChorePageState#d1d35
I/flutter (28856): A
I/xxxxxxx.tms_ap(28856): ProcessProfilingInfo new_methods=403 is saved saved_to_disk=1 resolve_classes_delay=8000
I/flutter (28856): _ChorePageState#d1d35
I/flutter (28856): B
I/flutter (28856): _ChorePageState#d1d35
I/flutter (28856): C
Vertumnus answered 5/7, 2020 at 14:2 Comment(0)
B
15

Struggled with what I think is the same issue today and the solution ended up being to pass a String key to the StatefulWidget constructor. So in your example:

  List<Widget> _children = [
    new ChorePage(key: Key('A'), Title:'A'),
    new ChorePage(key: Key('B'), Title:'B'),
    new ChorePage(key: Key('C'), Title:'C')
  ];
Baseline answered 26/11, 2020 at 10:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.