Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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
like image 624
Amdixer Avatar asked Jul 05 '20 14:07

Amdixer


People also ask

How do you pass data from one stateful widget to another in flutter?

Steps to Pass Data to Stateful Widget in Flutter To pass data to stateful widget, first of all, create two pages. Now from the first page open the second page and pass the data. Inside the second page, access the variable using the widget. For example widget.


1 Answers

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')
  ];
like image 72
Pjotr Gainullin Avatar answered Oct 19 '22 03:10

Pjotr Gainullin