Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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),
        ]));
  }
}    
like image 706
tmaihoff Avatar asked Jul 18 '19 15:07

tmaihoff


1 Answers

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!

like image 137
Hemanth Raj Avatar answered Oct 16 '22 09:10

Hemanth Raj