Search code examples
flutterstatefulwidget

Flutter accessing State class variable of StatefulWidget from a different class


I have a StatefulWidget class 'FirstClass' which extends a State '_FirstClassState'. From a separate State class, called '_SecondClassState', I'm trying to access the value of a variable (called 'counter' in '_FirstClassState').

I've found a solution, but I'm not sure if this is the best solution to the problem. I've tried looking at other similar questions:

  • How to access Stateful widget variable inside State class outside the build method? (Declaring the variable in the StatefulWidget class and using 'widget.' in the State class does not allow me to get the value of 'counter' from '_SecondClassState')
  • I've also seen other sites that recommend using a GlobalKey. However, even though this might be a solution, I didn't explore further into this as I found other sites which recommend minimising the use of GlobalKeys

second_class.dart:

import 'package:brew_crew/question/first_class.dart';
import 'package:flutter/material.dart';

class SecondClass extends StatefulWidget {
  @override
  _SecondClassState createState() => _SecondClassState();
}

class _SecondClassState extends State<SecondClass> {
  final FirstClass firstClass = FirstClass();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("MyApp"),
        centerTitle: true,
      ),
      body: Column(
        children: <Widget>[
          firstClass, //Displays the button to increase 'counter'
          FlatButton(
              child: Text("Submit"),
              onPressed: () {
                print(firstClass
                    .getCounter()); //I need to get the value of 'counter' here to use elsewhere
              }),
        ],
      ),
    );
  }
}

first_class.dart

import 'package:flutter/material.dart';

class FirstClass extends StatefulWidget {
  final _FirstClassState firstClassState = _FirstClassState();

  @override
  _FirstClassState createState() => firstClassState;

  int getCounter() {
    return firstClassState.counter;
  }
}

class _FirstClassState extends State<FirstClass> {
  int counter = 0;

  //Increases counter by 1
  void _increaseCounter() {
    setState(() {
      counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    //A button which increases counter when clicked
    return FlatButton.icon(
      icon: Icon(Icons.add),
      label: Text("Counter: $counter"),
      onPressed: () {
        _increaseCounter();
      },
    );
  }
}

As you can see, within 'FirstClass', I initialise a new instance of '_FirstClassState'. Using this in the 'getCounter()' function, I can get the 'counter' value.

Is there a better way (e.g. best practice, fewer lines of code, an easier to understand method, etc.) than this to achieve what I'm trying to do?


Solution

  • The use of GlobalKey is definitely the recommended approach if absolutely you have to access the state of a widget from outside. However, in this case, you shouldn't use either approach.

    _SecondClassState should contain the counter, and you should pass it, along with the increaseCounter function, as parameters to FirstClass. If you want to increase the number, just call that function.

    Something along these lines:

    class SecondClass extends StatefulWidget {
      @override
      _SecondClassState createState() => _SecondClassState();
    }
    
    class _SecondClassState extends State<SecondClass> {
      int counter = 0;
    
      //Increases counter by 1
      void _increaseCounter() {
        setState(() {
          counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("MyApp"),
            centerTitle: true,
          ),
          body: Column(
            children: <Widget>[
              FirstClass(counter: counter, increaseCounter: _increaseCounter), //Displays the button to increase 'counter'
              FlatButton(
                  child: Text("Submit"),
                  onPressed: () {
                    print(counter.toString()); //I need to get the value of 'counter' here to use elsewhere
                  }),
            ],
          ),
        );
      }
    }
    
    class FirstClass extends StatefulWidget {
      final int counter;
      final Function increaseCounter;
    
      FirstClass({this.counter, this.increaseCounter});
    
      final _FirstClassState firstClassState = _FirstClassState();
    
      @override
      _FirstClassState createState() => firstClassState;
    }
    
    class _FirstClassState extends State<FirstClass> {
      @override
      Widget build(BuildContext context) {
        //A button which increases counter when clicked
        return FlatButton.icon(
          icon: Icon(Icons.add),
          label: Text("Counter: ${widget.counter}"),
          onPressed: () {
            widget.increaseCounter();
          },
        );
      }
    }