Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force an immediate redraw for a futurebuilder when state is changed?

Tags:

flutter

When I change the state upon which a specific futurebuilder widget relies, the widget is not redrawn until the async task completes. I want the widget to be redrawn immediately once the state changes. Below is the code for the futurebuilder:

child: new FutureBuilder(
            future: _api.getListOfTourneys(searchTerm, filterChecks, pageNum),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                if(!(snapshot.data is List)){
                  return new TourneyItem(snapshot.data['tournament']);
                }
                return new Expanded(
                    child: ListView.builder(
                  shrinkWrap: false,
                  scrollDirection: Axis.vertical,
                  itemCount: snapshot.data.length,
                  itemBuilder: (BuildContext context, int index) {
                    return TourneyItem(snapshot.data[index]);
                  },
                ));
              } else if (snapshot.hasError) {
                return new Text("No results found");
              } else {
                return new CircularProgressIndicator();
              }
            },
          )
like image 409
Marshall Gordon Avatar asked Jun 22 '18 03:06

Marshall Gordon


2 Answers

I think FutureBuilder only builds once at start then everytime async task is compelted. So when we navigate to screen FutureBuilder is build at start then when async task is complete, then for other calls (except first) FutureBuilder only builds after async task is completed.

I also needed rebuild FutureBuilder at start of async call, I solved this issue by using snapshot.connectionState

Insider builder of FutureBuilder

if(snapshot.connectionState == ConnectionState.done){
    if(snapshot.hasData){
        //Show data here
    }else{
       //Show error here
    }
}else{
    //Show progress
}
like image 130
Dhiraj Sharma Avatar answered Nov 14 '22 22:11

Dhiraj Sharma


You can't do that using FutureBuilder. If you want to build more than "initial" + "done" don't use FutureBuilder.

Instead you can use a Stream and StreamBuilder by submitting your future result to the stream.

class Foo extends StatefulWidget {
  @override
  _FooState createState() => _FooState();
}

class _FooState extends State<Foo> {
  StreamController streamController;

  @override
  void initState() {
    load();
    super.initState();
  }

  load() async {
    streamController.add("Loading");
    await Future.delayed(Duration(seconds: 1));
    streamController.add("Done");
  }

  @override
  void didUpdateWidget(Foo oldWidget) {
    if (somethingChanged) {
      load();
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
    void dispose() {
      streamController.close();
      super.dispose();
    }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<String>(
      stream: streamController.stream,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return new Text(snapshot.data);
        } else if (snapshot.hasError) {
          return new Text("Error");
        } else {
          return new Text("Nothing");
        }
      },
    );
  }
}
like image 33
Rémi Rousselet Avatar answered Nov 14 '22 21:11

Rémi Rousselet