Jorge Restrepo
Jorge Restrepo

Reputation: 59

setState dont work inside ontap async on a futureBuilder

Hello and thanks for reading this, i was trying to call a setState inside a onTap() function that is inside a FutureBuilder i was reading other threads with similar problems, but i can't find a fix, there say that problem is the setState dont works fine with async.

i call setState cause i have a ExpansionTile with ListTiles with remote data, see the code, i try to update the data gattering when i tap another option, but when i call setState the data gattering is maded but nothing happens in UI.

I tried to put the setState call in the whenComplete of the async onTap, but still no working, i readed that if i put a symbolic return and after the setState but still no working, i tried to put in different points of the async, i tried to delete the showSnackBar and see if it works with only the new data gattering function and setState, but dont works.

i hope you can uderstand me, here is a little piece of my code, if you need more, let me know:

                           ExpansionTile(
                              collapsedTextColor: Colors.black87,
                              textColor: Colors.white,
                              collapsedBackgroundColor: Colors.white,
                              backgroundColor: Colors.blue,
                              title: Text(element['result'] == ''
                                  ? AppLocalizations.of(context)!.noTileSelected
                                  : element['result']),
                              children: List<Widget>.generate(
                                  6,
                                  (index) => index == 0
                                      ? ListTile(
                                          onTap: () async {
                                            bool res = await analisisModel
                                                .updateField(
                                              '',
                                              element['id'].toString(),
                                              bach,
                                              id,
                                            )
                                                .whenComplete(() {
                                              return;
                                            });

                                            if (res) {
                                              ScaffoldMessenger.of(context)
                                                  .showSnackBar(SnackBar(
                                                content: Text(
                                                    AppLocalizations.of(
                                                            context)!
                                                        .savedSnack),
                                                duration:
                                                    Duration(milliseconds: 500),
                                              ));
                                            } else {
                                              ScaffoldMessenger.of(context)
                                                  .showSnackBar(SnackBar(
                                                content: Text(
                                                    AppLocalizations.of(
                                                            context)!
                                                        .errorSnack),
                                                duration: Duration(
                                                    milliseconds: 1500),
                                              ));
                                            }
                                            setState(() {
                                              this._future =
                                                  analisisModel.getFinalData(
                                                      idCue, bach, id);
                                            });
                                          },
                                          title: Text(
                                            '---',
                                            style:
                                                TextStyle(color: Colors.white),
                                          ),
                                        )
                                      : ListTile(
                                          title: Text(
                                              element['opci$index'] == ''
                                                  ? AppLocalizations.of(
                                                          context)!
                                                      .noRegistersText
                                                  : element['opci$index'],
                                              style: TextStyle(
                                                  color: Colors.white)),
                                          onTap: () async {
                                            bool res = await analisisModel
                                                .updateField(
                                              element['opci$index'],
                                              element['id'].toString(),
                                              bach,
                                              id,
                                            )
                                                .whenComplete(() {
                                              return;
                                            });

                                            if (res) {
                                              ScaffoldMessenger.of(context)
                                                  .showSnackBar(SnackBar(
                                                content: Text(
                                                    AppLocalizations.of(
                                                            context)!
                                                        .savedSnack),
                                                duration:
                                                    Duration(milliseconds: 500),
                                              ));
                                            } else {
                                              ScaffoldMessenger.of(context)
                                                  .showSnackBar(SnackBar(
                                                content: Text(
                                                    AppLocalizations.of(
                                                            context)!
                                                        .errorSnack),
                                                duration: Duration(
                                                    milliseconds: 1500),
                                              ));
                                            }
                                            setState(() {
                                              this._future =
                                                  analisisModel.getFinalData(
                                                      idCue, bach, id);
                                            });
                                          },
                                        ))))

this is the piece of code that doesn't work, i've deleted showSnacBar for easier reading:

ListTile(
   onTap: () async {
      bool res = await analisisModel.updateField(
                    '',
                    element['id'].toString(),
                    bach,
                    id,
                 ).whenComplete(() { return;});
      //that set state don't make anything in UI
      setState(() {
           this._future = analisisModel.getFinalData(
                             idCue, bach, id);
      });
    },
    title: Text('---',
                style:  TextStyle(color: Colors.white),
            ),
)

Upvotes: 0

Views: 440

Answers (1)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63559

while using FutureBuilder we promised to wait only once. and it will rebuild only once, if you are trying to modify value like using setState inside FutureBuilder or even outside of that widget, it will rebuild everything. better you can use stateManagement for this situation.

here is an example how FutureBuilder rebuild everytime.


class CalculatableTextFormField extends StatefulWidget {
  @override
  _CalculatableTextFormFieldState createState() =>
      _CalculatableTextFormFieldState();
}

class _CalculatableTextFormFieldState extends State<CalculatableTextFormField> {
  int data = 0;
  int _numberOfFuture = 0;

  Future<int> dummyFuture() async {
    print("future called ${_numberOfFuture++}");
    return Future.delayed(Duration(seconds: 1)).then((value) => 4);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
      children: [
        Text("inside FutureBuilder"),
        FutureBuilder<int>(
          future: dummyFuture(),
          builder: (context, snapshot) {
            if (snapshot.hasData &&
                snapshot.connectionState == ConnectionState.done) {
              return Column(
                children: [
                  Builder(
                    builder: (context) {
                      return Text(
                        "Got Data from Future $data",
                        key: ValueKey("text"),
                      );
                    },
                  ),
                  ElevatedButton(
                    onPressed: () async {
                      bool result = await Future.delayed(Duration(seconds: 2))
                          .then((value) => true);
                      if (result)
                        setState(() {
                          data++;
                        });

                      print("after click $data");
                    },
                    child: Text(
                      "Click",
                    ),
                  ),
                ],
              );
            } else
              return CircularProgressIndicator();
          },
        ),
        ElevatedButton(
            onPressed: () {
              setState(() {});
            },
            child: Text("just setState")),
      ],
    ));
  }
}

Upvotes: 1

Related Questions