How to pass data by reference to stateful widget? I want to change a variable inside a stateful widget and update original variable

3,553

Actually the StatefulWidget is immutable and its state is maintained by the State class. You cannot pass values by reference and update the widgets. Instead you can just pass the value and and a function that updates the value.

Example:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter([int value]) {
    setState(() {
      _counter = value ?? (_counter + 1);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              'Counter inside main layout tree: $_counter',
              style: Theme.of(context).textTheme.title,
            ),
            TestWidget(
              counter: _counter,
              updateCount: _incrementCounter,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class TestWidget extends StatelessWidget {
  final int counter;
  final ValueChanged<int> updateCount;

  const TestWidget({Key key, this.counter, this.updateCount}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Card(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.all(Radius.circular(10)),
        side: BorderSide(color: Colors.orange),
      ),
      child: Column(
        children: <Widget>[
          Text("This card is an external Widget"),
          Slider(
            min: 0,
            max: 100,
            divisions: 101,
            onChanged: (double val) {
              updateCount(val.toInt());
            },
            value: counter.toDouble(),
          ),
          Text(
            "Counter inside external widget: $counter",
            style: Theme.of(context).textTheme.title,
          ),
        ],
      ),
    );
  }
}

Hoper that helps!

Share:
3,553
tmaihoff
Author by

tmaihoff

Updated on December 12, 2022

Comments

  • tmaihoff
    tmaihoff over 1 year

    I want to pass data to a stateful widget, change the data inside the widget and also have it updated in the original location.

    I want to avoid global variables and I am wondering if I can pass a variable to a stateful widget by reference.

    Here is some example code where data is passed to the widget. If I use the slider, the counter is only update inside the widget, not in the main layout tree.

    I appreciate any help.

    import 'package:flutter/material.dart';
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      void _incrementCounter() {
        setState(() {
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  'Counter inside main layout tree: $_counter',
                  style: Theme.of(context).textTheme.title,
                ),
                TestWidget(_counter),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
      }
    }
    
    class TestWidget extends StatefulWidget {
      int counter;
      TestWidget(this.counter);
      @override
      _TestWidgetState createState() => _TestWidgetState();
    }
    
    class _TestWidgetState extends State<TestWidget> {
      @override
      Widget build(BuildContext context) {
        return Card(
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.all(Radius.circular(10)),
              side: BorderSide(color: Colors.orange),
            ),
            child: Column(children: <Widget>[
              Text("This card is an external Widget"),
              Slider(
                min: 0,
                max: 100,
                divisions: 101,
                onChanged: (double val) {
                  setState(() {
                    widget.counter = val.toInt();
                  });
                },
                value: widget.counter.toDouble(),
              ),
              Text("Counter inside external widget: ${widget.counter}",
                  style: Theme.of(context).textTheme.title),
            ]));
      }
    }