Search code examples
flutterfuturesetstate

Refresh ui without reload data in FutureBuilder is possible?


I have an app which id using random data from api backend and I have a float action button to add current data to favorite, when I clicked to favorite button the icon needs to change according to a bool value(it named recorded() in my example), but I only can do that with setState(to rebuild page) but this time data of whole page is changing because my api answer is random with same url, I mean anytime I add or delete current data the page reloading with another random data, I need to bypass this data reload(getData() part in my example) and just refresh the icon of my favorite button, is there any way to do that, I tried to use another FutureBuilder for floataction button and setState for only recorded() but still same result?

My construction tree is like this:

 @override
  Widget build(BuildContext context) {
    return Material(
      child: FutureBuilder<Payload>(
          future: getData(_name),
          builder: (context, snapshot) {
          Future<bool> recorded()async {
              var checkFavs = await favoriteDao.findRecordById(snapshot.data.id);
              return checkFavs == null ? Future<bool>.value(true) : Future<bool>.value(false);
            }
           if (snapshot.connectionState != ConnectionState.done && firstRun == true)
              return Center(child: Image.asset("images/dice.gif"));
            if (snapshot.connectionState == ConnectionState.done)
              if (snapshot.hasError)
              {
                return Scaffold(...) // error page
              }
              return Scaffold(..
              ....
              ....
              floatingActionButton:  FutureBuilder(
                            future: recorded(),
                            builder: (context, AsyncSnapshot snapshots){
                              return FloatingActionButton(
                               onPressed: () async{
                                  firstRun = false;
                                  var myrecord = Myrecord(//data details for record//)
                                  var checkFavs = await favoriteDao.findRecordById(snapshot.data.id);
                                  if (checkFavs == null) {await favoriteDao.insertRecord(myrecord);}
                                  else {await favoriteDao.deleteById(snapshot.data.id);}
                                  setState(() {
                                      recorded(); 
                                    });
                                  },
                                  child: snapshots.hasData && snapshots.data ? Icon (Icon ( Icons.favorite_border,) : Icon (Icons.favorite,)
                              };
                             )
                            )
                           ...

Solution

  • You should not create the Future in the FutureBuilder but in the initState method

    @override
    void initState() {
      _getData = getData(_name)
      super.initState()
    }
    
    @override
    Widget build() {
      return FutureBuilder<Payload>(
        future: _getData,
        builder: (context, snapshot) {
          // your code
        }
      );
    }
    

    because build() will be called after setState, you should separate the creation of the Future and the build method