Search code examples
flutterdartflutter-layoutflutter-state

How to setState does work in my flutter code?


https://github.com/kangsudal/performance_tracker/blob/main/lib/main.dart


class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    String str_addUpToFirst = '''
    int addUpToFirst(n) {
      var total = 0;
      for (var i = 0; i <= n; i++) {
        total += i;
      }
      return total;
    }
    ''';
    int addUpToFirst(n) {
      var total = 0;
      for (var i = 0; i <= n; i++) {
        total += i;
      }
      return total;
    }
    Duration duration = Duration(microseconds: 0);

    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: Container(
              width: double.infinity,
              color: Colors.blue,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text("Performance Tracker"),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      ElevatedButton(
                        onPressed: () {

                          setState(() {
                            Stopwatch stopwatch = new Stopwatch()..start();
                            addUpToFirst(10000000);
                            duration = stopwatch.elapsed;
                          });
                          print(
                              'addUpToFirst() executed in ${duration}');
                        },
                        child: Text("addUpToFirst"),
                      ),
                      ElevatedButton(
                        onPressed: () {},
                        child: Text("addUpToSecond"),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Container(
                          decoration: BoxDecoration(),
                          width: 50,
                          child: TextField()),
                      ElevatedButton(
                        onPressed: () {},
                        child: Text('Plot!'),
                      ),
                    ],
                  )
                ],
              ),
            ),
            flex: 1,
          ),
          Expanded(
            child: Container(
              // color: Colors.black,
              child: Row(
                children: [
                  Expanded(
                    child: Container(
                      color: Colors.grey,
                      child: Padding(
                        padding: EdgeInsets.only(top: 20),
                        child: Align(
                          alignment: Alignment.topCenter,
                          child: LayoutBuilder(
                            builder: (context, constraints) {
                              return Container(
                                color: Colors.yellow[100],
                                width: constraints.maxWidth * 0.9,
                                height: constraints.maxHeight * 0.5,
                                child: Text(str_addUpToFirst),
                              );
                            },
                          ),
                        ),
                      ),
                    ),
                  ),
                  Expanded(
                    child: Container(
                      color: Colors.white,
                      child: Text('$duration'),
                    ),
                  ),
                ],
              ),
            ),
            flex: 2,
          ),
        ],
      ),
    );
  }
}

enter image description here

enter image description here

In onpressed(), print works. "addUpToFirst() executed in 0:00:00.047199" I expected duration value should be changed to 0:00:00.047199. in layout. but it isn't. still 0. I don't know why setState change duration value in layout. I need help. Thank you.


Solution

  • You're not using any state variable.

    In a StatefulWidget you usually have some class properties (or variables), whereas you're declaring everything inside your build method. Here's the problem. You should move that variable outside the build method and make it a class property.

    You always had 0 in your layout because, even though you correctly invoke and use setState to update duration, every time setState is called, by definition the build method is re-run and therefore you re-initialize duration to zero in the next rebuild.

    This is why the print statement worked (it's in the button callback and executes in its own scope) while the layout didn't.

    Code (I didn't test it):

    import 'package:flutter/material.dart';
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      var duration = Duration(microseconds: 0);  // This is the only change!
      
      @override
      Widget build(BuildContext context) {
        String str_addUpToFirst = '''
        int addUpToFirst(n) {
          var total = 0;
          for (var i = 0; i <= n; i++) {
            total += i;
          }
          return total;
        }
        ''';
        int addUpToFirst(n) {
          var total = 0;
          for (var i = 0; i <= n; i++) {
            total += i;
          }
          return total;
        }
    
        return Scaffold(
          body: Column(
            children: [
              Expanded(
                child: Container(
                  width: double.infinity,
                  color: Colors.blue,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text("Performance Tracker"),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          ElevatedButton(
                            onPressed: () {
                              setState(() {
                                Stopwatch stopwatch = new Stopwatch()..start();
                                addUpToFirst(10000000);
                                duration = stopwatch.elapsed;
                              });
                              print('addUpToFirst() executed in ${duration}');
                            },
                            child: Text("addUpToFirst"),
                          ),
                          ElevatedButton(
                            onPressed: () {},
                            child: Text("addUpToSecond"),
                          ),
                        ],
                      ),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Container(
                              decoration: BoxDecoration(),
                              width: 50,
                              child: TextField()),
                          ElevatedButton(
                            onPressed: () {},
                            child: Text('Plot!'),
                          ),
                        ],
                      )
                    ],
                  ),
                ),
                flex: 1,
              ),
              Expanded(
                child: Container(
                  // color: Colors.black,
                  child: Row(
                    children: [
                      Expanded(
                        child: Container(
                          color: Colors.grey,
                          child: Padding(
                            padding: EdgeInsets.only(top: 20),
                            child: Align(
                              alignment: Alignment.topCenter,
                              child: LayoutBuilder(
                                builder: (context, constraints) {
                                  return Container(
                                    color: Colors.yellow[100],
                                    width: constraints.maxWidth * 0.9,
                                    height: constraints.maxHeight * 0.5,
                                    child: Text(str_addUpToFirst),
                                  );
                                },
                              ),
                            ),
                          ),
                        ),
                      ),
                      Expanded(
                        child: Container(
                          color: Colors.white,
                          child: Text('$duration'),
                        ),
                      ),
                    ],
                  ),
                ),
                flex: 2,
              ),
            ],
          ),
        );
      }
    }