flutter - FutureBuilder auto rebuild each time press a button in the screen

2.3k views Asked by At

I try to use FutureBuilder in Flutter to wait ulti my initState is finished then buil the UI for the app. But when the app is running, the screen keep rebuilding each time I press another button (the button does totally different thing).

Future loadUser() async {
    String jsonString = await storage.read(key: "jwt");
    final jsonResponse = json.decode(jsonString);
    loggedUser = new LoggedUser.fromJson(jsonResponse);
    print(loggedUser.token);
    getProfile();
    getJourneyByUserId()
        .then((receivedList){
      addRanges(receivedList);});
    }

Future<List<Journey>>getJourneyByUserId() async {
    var res = await http.get(
      Uri.parse("$baseUrl/journeys/userid=${loggedUser.user.userId}"),
      headers: {
        'Content_Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ${loggedUser.token}',
      },
    );
    if (res.statusCode == 200) {
      print("Get journeys successfully");
    }
    var data = jsonDecode(res.body);
    List idList = [];
    for (var i in data) {
      idList.add(i["journeyId"]);
    }
    for (var i in idList) {
      var res = await http.get(
        Uri.parse("$baseUrl/journeys/$i"),
      );
      var data = jsonDecode(res.body);
      Journey userJourney = new Journey.fromJson(data);
      setState(() {
        journeyList.add(userJourney);
      });
    }
    print("Journey ${journeyList.length}");
    return journeyList;
  }

addRanges(journeyList){
    setState(() {
      rangeList=[];
    });
      if (journeyList.isNotEmpty) {
        for (var i in journeyList) {
          DateTime startDate =
          DateTime(i.startDate.year, i.startDate.month, i.startDate.day);
          DateTime endDate =
          DateTime(i.endDate.year, i.endDate.month, i.endDate.day);
          setState(() {
            rangeList.add(PickerDateRange(startDate, endDate));
          });
        }
      }
      print("Range ${rangeList.length}");
      return rangeList;
  }

returnRange() {
    List<PickerDateRange> list = [];
    for(int i =0; i<rangeList.length;i++){
      list.add(rangeList[i]);
    }
    return list;
  }

Future functionForBuilder() async {
    return await returnRange();
  }

//initState function
  @override
  void initState() {
    super.initState();
    loadUser();
    functionForBuilder();
  }

//build the UI
Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("$_name's Profile",style: TextStyle(color: kColorPalette4),),
          centerTitle: true,
        ),
        body: Container(
          child: FutureBuilder(
            future: functionForBuilder(),
            builder: (BuildContext context,AsyncSnapshot snapshot){
            //here I set the condition for each case of snapshot
}

I have read some documents say that I should assign the functionForBuilder() to a Future variable when initState then use it in the future child of FutureBuilder. Example:

Future _future;

//initState function
  @override
  void initState() {
    super.initState();
    loadUser();
    _future=functionForBuilder();
  }

// then with the FutureBuilder
future: _future

With this way the screen is not rebuild anymore but my function returnRange() seems like not running as my expextation (I called the returnRange() once in the build() function).

Thanks in advance for your answer!

3

There are 3 answers

1
caiopo On

Whenever you assign to the _future variable again, you must do that inside a setState block, otherwise the widget will not rebuild with the new future.

For example:

void updateData() {
  setState(() {
      _future = functionForBuilder();
  });
}
1
Rakesh Saini On

If you use FutureBuilder, it rebuild items again and again.

Try two ways:

  1. Don't use `future: functionForBuilder(), comment it.
  2. Remove FutureBuilder(), simply use Container().

And let me know any issue?

1
Shahryar Rafique On

Code:

call your future in the initstate method not in the build as shown in the example.

class MyPage extends StatefulWidget { @override State<MyPage> createState() => _MyPageState(); } class _MyPageState extends State<MyPage> { // Declare a variable. late final Future<int> _future; @override void initState() { super.initState(); _future = _calculate(); // Assign your Future to it. } // This is your actual Future. Future<int> _calculate() => Future.delayed(Duration(seconds: 3), () => 42); @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<int>( future: _future, // Use your variable here (not the actual Future) builder: (_, snapshot) { if (snapshot.hasData) return Text('Value = ${snapshot.data!}'); return Text('Loading...'); }, ), ); } }