I was wondering what would be the best way to access/pass variables between widgets. For example,

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  int number = 0;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Jungle Book',
      home: new Scaffold(
        appBar: new AppBar(title: new Text('Jungle Book')),
        drawer: new AppMenu(),
        body: new MainPageManager(),
        floatingActionButton: new FloatingActionButton(onPressed: null,child: new Icon(Icons.shuffle),),
      ),
    );
  }
}

class MainPageManager extends StatefulWidget {
  @override
  _MainPageManagerState createState() => _MainPageManagerState();
}

class _MainPageManagerState extends State<MainPageManager> {
  List<String> keys = ["flamingo"];  // more to add later
  final _random = new Random();

  @override
  Widget build(BuildContext context) {
    return Center(
      child: new Image.asset('images/'+keys[_random.nextInt(keys.length)]+'.jpg',
        fit: BoxFit.fill,)
    );
  }
}

If I need to pass a value during the floatingActionButton.OnPressed to the MainPageManager, what would be best way to do it.

What am attempting to do is, when the FloatingActionButton is pressed, i need to update the MainPageManager with a new image.

I read somewhere that using Global keys is not a good idea. What could be alternative ? PS: am more of a beginner with flutter.


Solution 1: Philip Feldmann

Flutter is not opinionated about how you approach state management.

Since MainPageManager is a direct child of MyApp you could turn MyApp into a stateful widget and MainPageManager into a stateless widget instead, as you are not using the setState method at all in your MainPageManager. Then, in your onPressed callback you'd use the setState method to set the state of your MyApp component, which will cause flutter to rebuild MyApp and all child widgets (so MainPageManager will be rebuild as well).

The last thing to do would be to add a property to your now stateless MainPageManager, that you'd pass down to that component.

Example:

class MainPageManager extends StatelessWidget {
  final String value;

  MainPageManager({this.value});

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("$value"),
    );
  }
}

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _valueBinding;

  @override
  void initState() {
    _valueBinding = "Test";
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: <Widget>[
        MainPageManager(
          value: _valueBinding,
        ),
        MaterialButton(onPressed: () {
          setState(() {
            _valueBinding = "This will be shown in MainPageManager";
          });
        }, child: Text("Update Value"),)
      ],
    );
  }
}

For more complex use-cases:

Flutter comes with a state-management solution called InheritedWidget. However, the API is not that convenient and the flutter team actually promotes using a package called Provider instead, which builds on InheritedWidget.

If your app grows really big I actually recommend using the BloC pattern instead.