Flutter async convention/best practices for State and Widget











up vote
0
down vote

favorite












Coding with async/await/... can be done in many different ways. Is there an official pattern/convention/set of best practices?



In the code example below I have used (inconsistently) State related calls, data flags to drive Widget behaviours...(I didn't use FutureBuilder or StreamBuilder as explained in this post Flutter: Best Practices of Calling Async Codes from UI to focus on other ways).



All these different ways technically work but the code can become messy and bad for maintenance/team work. Any guidelines/convention on how to do it?



3 questions in the comments of the code...showing it all as I have also seen some people struggling with making it work (in case it helps)



//Don't forget the dependencies in the pubspec.yaml
//dependencies:
// flutter:
// sdk: flutter
// sqflite: any
// path_provider: any

import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:async';
import 'dart:io';

//for the DB
final String tblUsers = "users";
final String colUserid = "userid";
final String colDisplayName = "displayName";


//nothing interesting until the next comment
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@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();
}


//Focus for the discussion
class _MyHomePageState extends State<MyHomePage> {
DataBroker data;
bool dataLoaded=false;
//These are just to play with async data fetching/loading...no functional need for that
User user;
User userTwo;

_MyHomePageState();

//I want my database to be ready before I do anything...so I put all the init data at the beginning
@override
void initState() {
super.initState();

//Calling a function with all the sequential data fetching I need to init
//this doesn't prevent the UI from being created so some objects will be null until populated
initData().then((result) {
setState(() {
//I now know that the db has been initialised
dataLoaded=true;
});
});
}

Future<void> initData() async {
data = DataBroker();
//The await ensures that I don't fetch User data before the db has been initialised
await data.initialise();
//the await ensures I have user set before I assign it to userTwo
await data.getUser().then((u) {user=u;});
//Question 1: is it better to do it here
//Or put the 'userTwo = user' in the then()?
userTwo = user;
}

//No functional sense, i basically just want to get 'user' to be one step ahead of 'userTwo'
void _updateUser() {
user.displayName = user.displayName + '+';
data.getUser().then((res) {userTwo=res;});
data.updateUser(user).then((res){
//Empty function, just triggering setState to rebuild the UI
//Question 2: I am setting variables outside setState...should I be doing it another way?
setState(() {});
});
}

//Yet another pattern, here I directly create a function to display what I want while waiting for flags to be set
//Question 3: if I do that, I will end up with a lot of mini functions to show Widgets in 2 different cases
Widget _dataStatusWidget() {
if(dataLoaded) {
return Text('Data has been loaded');
} else {
return Text('Data is loading please wait...');
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_dataStatusWidget(),
//This will show null in the beginning as they are going to be displayed before the data is available
Text(
'User: ' + user.toString(),
),
//This will show null in the beginning as they are going to be displayed before the data is available
Text(
'UserTwo: ' + userTwo.toString(),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _updateUser,
tooltip: 'update user',
child: Icon(Icons.update),
),
);
}
}

//simple data access class...nothing amazing
class DataBroker {
static final DataBroker _databroker = new DataBroker._internal();
static final _dbName = "dbtest.db";
static Database _db;

DataBroker._internal();

factory DataBroker() {
return _databroker;
}

Database get db => _db;

Future<User> getUser() async {
List<Map> maps = await _db.query(
tblUsers,
columns: [colUserid, colDisplayName],
);
if (maps.length > 0) {
return new User.fromMap(maps.first);
}
return null;
}

Future<int> updateUser(User user) async {
return await _db.update(tblUsers, user.toMap(),
where: "$colUserid = ?", whereArgs: [user.userid]);
}


Future<void> initialise() async {
Directory dir = await getApplicationDocumentsDirectory();
String path = dir.path + _dbName;
await deleteDatabase(path);
_db = await openDatabase(path, version: 1, onCreate:_createDB);
}
}
//Creating the db with one user by default for simplicity
Future<Database> _createDB(Database db, int newVersion) async {
await db.execute('''
create table $tblUsers (
$colUserid integer primary key autoincrement,
$colDisplayName text
)''');

User user = User.withIDs(1,'John Doe');
await db.insert(tblUsers, user.toMap());
//just to be slow
await Future.delayed(Duration(milliseconds: 2000), () {});
return db;
}

//data class for completeness...nothing amazing
class User {
int _userid;
String _displayName;

User(this._displayName);
User.withIDs(this._userid, this._displayName);

int get userid => _userid;
String get displayName => _displayName;

set displayName(String displayName) {
_displayName = displayName;
}

String toString() {
return
"userid: " + _userid.toString() + "n" +
"displayName: " + _displayName + "n";
}

User.fromMap(dynamic o) {
this._userid=o["userid"];
this._displayName=o["displayName"];
}

Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
if (_userid != null) {
map["userid"] = _userid;
}
map["displayName"] = _displayName;
return map;
}
}









share|improve this question


























    up vote
    0
    down vote

    favorite












    Coding with async/await/... can be done in many different ways. Is there an official pattern/convention/set of best practices?



    In the code example below I have used (inconsistently) State related calls, data flags to drive Widget behaviours...(I didn't use FutureBuilder or StreamBuilder as explained in this post Flutter: Best Practices of Calling Async Codes from UI to focus on other ways).



    All these different ways technically work but the code can become messy and bad for maintenance/team work. Any guidelines/convention on how to do it?



    3 questions in the comments of the code...showing it all as I have also seen some people struggling with making it work (in case it helps)



    //Don't forget the dependencies in the pubspec.yaml
    //dependencies:
    // flutter:
    // sdk: flutter
    // sqflite: any
    // path_provider: any

    import 'package:flutter/material.dart';
    import 'package:sqflite/sqflite.dart';
    import 'package:path_provider/path_provider.dart';
    import 'dart:async';
    import 'dart:io';

    //for the DB
    final String tblUsers = "users";
    final String colUserid = "userid";
    final String colDisplayName = "displayName";


    //nothing interesting until the next comment
    void main() => runApp(MyApp());

    class MyApp extends StatelessWidget {
    @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();
    }


    //Focus for the discussion
    class _MyHomePageState extends State<MyHomePage> {
    DataBroker data;
    bool dataLoaded=false;
    //These are just to play with async data fetching/loading...no functional need for that
    User user;
    User userTwo;

    _MyHomePageState();

    //I want my database to be ready before I do anything...so I put all the init data at the beginning
    @override
    void initState() {
    super.initState();

    //Calling a function with all the sequential data fetching I need to init
    //this doesn't prevent the UI from being created so some objects will be null until populated
    initData().then((result) {
    setState(() {
    //I now know that the db has been initialised
    dataLoaded=true;
    });
    });
    }

    Future<void> initData() async {
    data = DataBroker();
    //The await ensures that I don't fetch User data before the db has been initialised
    await data.initialise();
    //the await ensures I have user set before I assign it to userTwo
    await data.getUser().then((u) {user=u;});
    //Question 1: is it better to do it here
    //Or put the 'userTwo = user' in the then()?
    userTwo = user;
    }

    //No functional sense, i basically just want to get 'user' to be one step ahead of 'userTwo'
    void _updateUser() {
    user.displayName = user.displayName + '+';
    data.getUser().then((res) {userTwo=res;});
    data.updateUser(user).then((res){
    //Empty function, just triggering setState to rebuild the UI
    //Question 2: I am setting variables outside setState...should I be doing it another way?
    setState(() {});
    });
    }

    //Yet another pattern, here I directly create a function to display what I want while waiting for flags to be set
    //Question 3: if I do that, I will end up with a lot of mini functions to show Widgets in 2 different cases
    Widget _dataStatusWidget() {
    if(dataLoaded) {
    return Text('Data has been loaded');
    } else {
    return Text('Data is loading please wait...');
    }
    }

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(
    title: Text(widget.title),
    ),
    body: Center(
    child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
    _dataStatusWidget(),
    //This will show null in the beginning as they are going to be displayed before the data is available
    Text(
    'User: ' + user.toString(),
    ),
    //This will show null in the beginning as they are going to be displayed before the data is available
    Text(
    'UserTwo: ' + userTwo.toString(),
    ),
    ],
    ),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: _updateUser,
    tooltip: 'update user',
    child: Icon(Icons.update),
    ),
    );
    }
    }

    //simple data access class...nothing amazing
    class DataBroker {
    static final DataBroker _databroker = new DataBroker._internal();
    static final _dbName = "dbtest.db";
    static Database _db;

    DataBroker._internal();

    factory DataBroker() {
    return _databroker;
    }

    Database get db => _db;

    Future<User> getUser() async {
    List<Map> maps = await _db.query(
    tblUsers,
    columns: [colUserid, colDisplayName],
    );
    if (maps.length > 0) {
    return new User.fromMap(maps.first);
    }
    return null;
    }

    Future<int> updateUser(User user) async {
    return await _db.update(tblUsers, user.toMap(),
    where: "$colUserid = ?", whereArgs: [user.userid]);
    }


    Future<void> initialise() async {
    Directory dir = await getApplicationDocumentsDirectory();
    String path = dir.path + _dbName;
    await deleteDatabase(path);
    _db = await openDatabase(path, version: 1, onCreate:_createDB);
    }
    }
    //Creating the db with one user by default for simplicity
    Future<Database> _createDB(Database db, int newVersion) async {
    await db.execute('''
    create table $tblUsers (
    $colUserid integer primary key autoincrement,
    $colDisplayName text
    )''');

    User user = User.withIDs(1,'John Doe');
    await db.insert(tblUsers, user.toMap());
    //just to be slow
    await Future.delayed(Duration(milliseconds: 2000), () {});
    return db;
    }

    //data class for completeness...nothing amazing
    class User {
    int _userid;
    String _displayName;

    User(this._displayName);
    User.withIDs(this._userid, this._displayName);

    int get userid => _userid;
    String get displayName => _displayName;

    set displayName(String displayName) {
    _displayName = displayName;
    }

    String toString() {
    return
    "userid: " + _userid.toString() + "n" +
    "displayName: " + _displayName + "n";
    }

    User.fromMap(dynamic o) {
    this._userid=o["userid"];
    this._displayName=o["displayName"];
    }

    Map<String, dynamic> toMap() {
    var map = Map<String, dynamic>();
    if (_userid != null) {
    map["userid"] = _userid;
    }
    map["displayName"] = _displayName;
    return map;
    }
    }









    share|improve this question
























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      Coding with async/await/... can be done in many different ways. Is there an official pattern/convention/set of best practices?



      In the code example below I have used (inconsistently) State related calls, data flags to drive Widget behaviours...(I didn't use FutureBuilder or StreamBuilder as explained in this post Flutter: Best Practices of Calling Async Codes from UI to focus on other ways).



      All these different ways technically work but the code can become messy and bad for maintenance/team work. Any guidelines/convention on how to do it?



      3 questions in the comments of the code...showing it all as I have also seen some people struggling with making it work (in case it helps)



      //Don't forget the dependencies in the pubspec.yaml
      //dependencies:
      // flutter:
      // sdk: flutter
      // sqflite: any
      // path_provider: any

      import 'package:flutter/material.dart';
      import 'package:sqflite/sqflite.dart';
      import 'package:path_provider/path_provider.dart';
      import 'dart:async';
      import 'dart:io';

      //for the DB
      final String tblUsers = "users";
      final String colUserid = "userid";
      final String colDisplayName = "displayName";


      //nothing interesting until the next comment
      void main() => runApp(MyApp());

      class MyApp extends StatelessWidget {
      @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();
      }


      //Focus for the discussion
      class _MyHomePageState extends State<MyHomePage> {
      DataBroker data;
      bool dataLoaded=false;
      //These are just to play with async data fetching/loading...no functional need for that
      User user;
      User userTwo;

      _MyHomePageState();

      //I want my database to be ready before I do anything...so I put all the init data at the beginning
      @override
      void initState() {
      super.initState();

      //Calling a function with all the sequential data fetching I need to init
      //this doesn't prevent the UI from being created so some objects will be null until populated
      initData().then((result) {
      setState(() {
      //I now know that the db has been initialised
      dataLoaded=true;
      });
      });
      }

      Future<void> initData() async {
      data = DataBroker();
      //The await ensures that I don't fetch User data before the db has been initialised
      await data.initialise();
      //the await ensures I have user set before I assign it to userTwo
      await data.getUser().then((u) {user=u;});
      //Question 1: is it better to do it here
      //Or put the 'userTwo = user' in the then()?
      userTwo = user;
      }

      //No functional sense, i basically just want to get 'user' to be one step ahead of 'userTwo'
      void _updateUser() {
      user.displayName = user.displayName + '+';
      data.getUser().then((res) {userTwo=res;});
      data.updateUser(user).then((res){
      //Empty function, just triggering setState to rebuild the UI
      //Question 2: I am setting variables outside setState...should I be doing it another way?
      setState(() {});
      });
      }

      //Yet another pattern, here I directly create a function to display what I want while waiting for flags to be set
      //Question 3: if I do that, I will end up with a lot of mini functions to show Widgets in 2 different cases
      Widget _dataStatusWidget() {
      if(dataLoaded) {
      return Text('Data has been loaded');
      } else {
      return Text('Data is loading please wait...');
      }
      }

      @override
      Widget build(BuildContext context) {
      return Scaffold(
      appBar: AppBar(
      title: Text(widget.title),
      ),
      body: Center(
      child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
      _dataStatusWidget(),
      //This will show null in the beginning as they are going to be displayed before the data is available
      Text(
      'User: ' + user.toString(),
      ),
      //This will show null in the beginning as they are going to be displayed before the data is available
      Text(
      'UserTwo: ' + userTwo.toString(),
      ),
      ],
      ),
      ),
      floatingActionButton: FloatingActionButton(
      onPressed: _updateUser,
      tooltip: 'update user',
      child: Icon(Icons.update),
      ),
      );
      }
      }

      //simple data access class...nothing amazing
      class DataBroker {
      static final DataBroker _databroker = new DataBroker._internal();
      static final _dbName = "dbtest.db";
      static Database _db;

      DataBroker._internal();

      factory DataBroker() {
      return _databroker;
      }

      Database get db => _db;

      Future<User> getUser() async {
      List<Map> maps = await _db.query(
      tblUsers,
      columns: [colUserid, colDisplayName],
      );
      if (maps.length > 0) {
      return new User.fromMap(maps.first);
      }
      return null;
      }

      Future<int> updateUser(User user) async {
      return await _db.update(tblUsers, user.toMap(),
      where: "$colUserid = ?", whereArgs: [user.userid]);
      }


      Future<void> initialise() async {
      Directory dir = await getApplicationDocumentsDirectory();
      String path = dir.path + _dbName;
      await deleteDatabase(path);
      _db = await openDatabase(path, version: 1, onCreate:_createDB);
      }
      }
      //Creating the db with one user by default for simplicity
      Future<Database> _createDB(Database db, int newVersion) async {
      await db.execute('''
      create table $tblUsers (
      $colUserid integer primary key autoincrement,
      $colDisplayName text
      )''');

      User user = User.withIDs(1,'John Doe');
      await db.insert(tblUsers, user.toMap());
      //just to be slow
      await Future.delayed(Duration(milliseconds: 2000), () {});
      return db;
      }

      //data class for completeness...nothing amazing
      class User {
      int _userid;
      String _displayName;

      User(this._displayName);
      User.withIDs(this._userid, this._displayName);

      int get userid => _userid;
      String get displayName => _displayName;

      set displayName(String displayName) {
      _displayName = displayName;
      }

      String toString() {
      return
      "userid: " + _userid.toString() + "n" +
      "displayName: " + _displayName + "n";
      }

      User.fromMap(dynamic o) {
      this._userid=o["userid"];
      this._displayName=o["displayName"];
      }

      Map<String, dynamic> toMap() {
      var map = Map<String, dynamic>();
      if (_userid != null) {
      map["userid"] = _userid;
      }
      map["displayName"] = _displayName;
      return map;
      }
      }









      share|improve this question













      Coding with async/await/... can be done in many different ways. Is there an official pattern/convention/set of best practices?



      In the code example below I have used (inconsistently) State related calls, data flags to drive Widget behaviours...(I didn't use FutureBuilder or StreamBuilder as explained in this post Flutter: Best Practices of Calling Async Codes from UI to focus on other ways).



      All these different ways technically work but the code can become messy and bad for maintenance/team work. Any guidelines/convention on how to do it?



      3 questions in the comments of the code...showing it all as I have also seen some people struggling with making it work (in case it helps)



      //Don't forget the dependencies in the pubspec.yaml
      //dependencies:
      // flutter:
      // sdk: flutter
      // sqflite: any
      // path_provider: any

      import 'package:flutter/material.dart';
      import 'package:sqflite/sqflite.dart';
      import 'package:path_provider/path_provider.dart';
      import 'dart:async';
      import 'dart:io';

      //for the DB
      final String tblUsers = "users";
      final String colUserid = "userid";
      final String colDisplayName = "displayName";


      //nothing interesting until the next comment
      void main() => runApp(MyApp());

      class MyApp extends StatelessWidget {
      @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();
      }


      //Focus for the discussion
      class _MyHomePageState extends State<MyHomePage> {
      DataBroker data;
      bool dataLoaded=false;
      //These are just to play with async data fetching/loading...no functional need for that
      User user;
      User userTwo;

      _MyHomePageState();

      //I want my database to be ready before I do anything...so I put all the init data at the beginning
      @override
      void initState() {
      super.initState();

      //Calling a function with all the sequential data fetching I need to init
      //this doesn't prevent the UI from being created so some objects will be null until populated
      initData().then((result) {
      setState(() {
      //I now know that the db has been initialised
      dataLoaded=true;
      });
      });
      }

      Future<void> initData() async {
      data = DataBroker();
      //The await ensures that I don't fetch User data before the db has been initialised
      await data.initialise();
      //the await ensures I have user set before I assign it to userTwo
      await data.getUser().then((u) {user=u;});
      //Question 1: is it better to do it here
      //Or put the 'userTwo = user' in the then()?
      userTwo = user;
      }

      //No functional sense, i basically just want to get 'user' to be one step ahead of 'userTwo'
      void _updateUser() {
      user.displayName = user.displayName + '+';
      data.getUser().then((res) {userTwo=res;});
      data.updateUser(user).then((res){
      //Empty function, just triggering setState to rebuild the UI
      //Question 2: I am setting variables outside setState...should I be doing it another way?
      setState(() {});
      });
      }

      //Yet another pattern, here I directly create a function to display what I want while waiting for flags to be set
      //Question 3: if I do that, I will end up with a lot of mini functions to show Widgets in 2 different cases
      Widget _dataStatusWidget() {
      if(dataLoaded) {
      return Text('Data has been loaded');
      } else {
      return Text('Data is loading please wait...');
      }
      }

      @override
      Widget build(BuildContext context) {
      return Scaffold(
      appBar: AppBar(
      title: Text(widget.title),
      ),
      body: Center(
      child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
      _dataStatusWidget(),
      //This will show null in the beginning as they are going to be displayed before the data is available
      Text(
      'User: ' + user.toString(),
      ),
      //This will show null in the beginning as they are going to be displayed before the data is available
      Text(
      'UserTwo: ' + userTwo.toString(),
      ),
      ],
      ),
      ),
      floatingActionButton: FloatingActionButton(
      onPressed: _updateUser,
      tooltip: 'update user',
      child: Icon(Icons.update),
      ),
      );
      }
      }

      //simple data access class...nothing amazing
      class DataBroker {
      static final DataBroker _databroker = new DataBroker._internal();
      static final _dbName = "dbtest.db";
      static Database _db;

      DataBroker._internal();

      factory DataBroker() {
      return _databroker;
      }

      Database get db => _db;

      Future<User> getUser() async {
      List<Map> maps = await _db.query(
      tblUsers,
      columns: [colUserid, colDisplayName],
      );
      if (maps.length > 0) {
      return new User.fromMap(maps.first);
      }
      return null;
      }

      Future<int> updateUser(User user) async {
      return await _db.update(tblUsers, user.toMap(),
      where: "$colUserid = ?", whereArgs: [user.userid]);
      }


      Future<void> initialise() async {
      Directory dir = await getApplicationDocumentsDirectory();
      String path = dir.path + _dbName;
      await deleteDatabase(path);
      _db = await openDatabase(path, version: 1, onCreate:_createDB);
      }
      }
      //Creating the db with one user by default for simplicity
      Future<Database> _createDB(Database db, int newVersion) async {
      await db.execute('''
      create table $tblUsers (
      $colUserid integer primary key autoincrement,
      $colDisplayName text
      )''');

      User user = User.withIDs(1,'John Doe');
      await db.insert(tblUsers, user.toMap());
      //just to be slow
      await Future.delayed(Duration(milliseconds: 2000), () {});
      return db;
      }

      //data class for completeness...nothing amazing
      class User {
      int _userid;
      String _displayName;

      User(this._displayName);
      User.withIDs(this._userid, this._displayName);

      int get userid => _userid;
      String get displayName => _displayName;

      set displayName(String displayName) {
      _displayName = displayName;
      }

      String toString() {
      return
      "userid: " + _userid.toString() + "n" +
      "displayName: " + _displayName + "n";
      }

      User.fromMap(dynamic o) {
      this._userid=o["userid"];
      this._displayName=o["displayName"];
      }

      Map<String, dynamic> toMap() {
      var map = Map<String, dynamic>();
      if (_userid != null) {
      map["userid"] = _userid;
      }
      map["displayName"] = _displayName;
      return map;
      }
      }






      flutter conventions






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 21 at 21:28









      Minh

      316




      316





























          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53420702%2fflutter-async-convention-best-practices-for-state-and-widget%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53420702%2fflutter-async-convention-best-practices-for-state-and-widget%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)