Flutter/Dart - How can I change the State of a StatefulWidget from another StatefulWidget in a different file?

Background: I have a StatefulWidget for a navbar that displays the icon of the current page as active. It already updates correctly if the user clicks in different icons from the navbar. But I also need it to update the active icon if the user clicks in a button outside of the navbar, whose code is located in a different StatefulWidget. To do so, I imagined that the function of the button should call a function from the navbar StatefulWidget, which uses setState and an index passed as a parameter to update the active icon. However, my attempts so far have not worked. The following error occurred:

The following assertion was thrown while handling a gesture:
I/flutter (24216): setState() called in constructor: TabsState#1bf6b(lifecycle state: created, no widget, not mounted) I/flutter (24216): This happens when you call setState() on a State object for a widget that hasn't been inserted into I/flutter (24216): the widget tree yet. It is not necessary to call setState() in the constructor, since the state is
I/flutter (24216): already assumed to be dirty when it is initially created.`}

The code from the parent widget was:

[...]
  Tabs({Key key, this.menuScreenContext, this.initialIndex}) : super(key: key);

  final int initialIndex;

  @override
  TabsState createState() => TabsState();
}

class TabsState extends State<Tabs> {
  PersistentTabController controller;

  @override
  void initState() {
    super.initState();
    controller = PersistentTabController(initialIndex: widget.initialIndex);
  }

  List<Widget> _buildScreens() {
    return [
      HomeScreen(),
[...]
void updateIndex(int index) {
    setState(() {
      controller.index = index;
    });
  }
}

Code from the child widget (class _HomeScreenState extends State ) :

[...]  
    CustomButton(
            function: () {
              final tabsState = TabsState();
              tabsState.updateIndex(2);
[...]

I tried to solve it by calling initState() at the child widget before calling setState(), but that did not work and as far as I understand, it creates another State object associated with the Stateful Widget, which seems like the wrong approach in this case since I only want to change the State of the existing navbar object.
My question is: how can I call this function updateIndex(int index), that uses setState to update the navbar active icon, from the Button function inside another StatefulWidget, located in a different file, successfully?

Upvotes: 2

Views: 1533

Answers (1)

I made it! Based on the answers to this question(Controlling State from outside of a StatefulWidget), I understood that a way to access the State of a different Stateful widget is to:

1-> Declare the State class that you want to change on the child widget stateful widget, using findAncestorStateOfType which finds an ancestor of that type. For example:

class HomeScreen extends StatefulWidget { 
  static TabsState of(BuildContext context) =>context.findAncestorStateOfType<TabsState>(); 

2-> call the function from wherever you need inside the state class of this stateful widget, referring to the stateful widget class and using "of(context)". For example:

function: () {
          HomeScreen.of(context).updateIndexFromCart(2);

3-> This function should be located inside the state class of the stateful widget that you previously referred, and then it is possible to use setState normally. For example:

void updateIndexFromCart(int index) {
setState(() {
  controller.index = index;
  cartScreenFlag = true;
});

}

Upvotes: 1

Related Questions