강수경
강수경

Reputation: 37

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.

Upvotes: 0

Views: 175

Answers (3)

Ke Nguyen Duc
Ke Nguyen Duc

Reputation: 116

The variable 'Duration duration = Duration(microseconds: 0)'is declared in Widget build, when you setstate, rebuild ui in build and assign the value of the variable to 0 again. You should put duration outside 'Widget build(BuildContext context) {...}'.

https://api.flutter.dev/flutter/widgets/State/setState.html

Upvotes: 1

Dev Hingu
Dev Hingu

Reputation: 197

When you call the setState method, the build method is called again. So the value that needs to be changed remains the same.

So instead of declaring variables inside the build method, you need to call variables outside the build method.

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

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

class _MyHomePageState extends State<MyHomePage> {
  Duration duration = const Duration(microseconds: 0);

  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;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: Container(
              width: double.infinity,
              color: Colors.blue,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const 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: const Text("addUpToFirst"),
                      ),
                      ElevatedButton(
                        onPressed: () {},
                        child: const Text("addUpToSecond"),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Container(
                          decoration: const BoxDecoration(),
                          width: 50,
                          child: const TextField()),
                      ElevatedButton(
                        onPressed: () {},
                        child: const Text('Plot!'),
                      ),
                    ],
                  )
                ],
              ),
            ),
            flex: 1,
          ),
          Expanded(
            child: Container(
              // color: Colors.black,
              child: Row(
                children: [
                  Expanded(
                    child: Container(
                      color: Colors.grey,
                      child: Padding(
                        padding: const 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,
          ),
        ],
      ),
    );
  }
}

Upvotes: 1

venir
venir

Reputation: 2087

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,
          ),
        ],
      ),
    );
  }
}

Upvotes: 1

Related Questions