Search code examples
flutterfuturesetstateflutter-futurebuilder

Flutter : unclear ValueChanged and FutureBuilder


I'm getting some data from my API. I handle them by converting the returned JSON into some widget CommentaireSingle.

But there's something unclear for my, about the I guess the build method.

  1. The build is called each time the widget is build, including the setState method.
  2. The FutureBuilder is used to generate the content once it's fully loaded.
  3. The ValueChanged is used to pass data from the children to it's parent.

So my question is : why each time that I do a setState, my Future is adding the original data to my view ? I have to clear the initial listCommentsWidgets is order to have the "logic" result (to not have twice the original list of widgets)

class _CommentairesListingState extends State<CommentairesListing> {
  List<Commentaire> listComments = [];
  Future loadListComments;
  List<Widget> listCommentsWidgets = [];

  @override
  void initState() {
    super.initState();
    loadListComments = _loadComments();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: loadListComments,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return generateComments();
        } else {
          return Center(
            child: SizedBox(
              height: 25,
              width: 25,
              child: CircularProgressIndicator(),
            ),
          );
        }
      },
    );
  }

  Future _loadComments() async {
    listComments = await MyWS()
        .getComs(widget.publication.pubId);
  }

  Expanded generateComments() {
    listCommentsWidgets.clear();
    for (Commentaire commentaire in listComments) {
      CommentaireSingle single = CommentaireSingle(
          ...
          toRemove: updateCommentaireListing, #ValueChanged
          responseTo: widget.responseTo);
      listCommentsWidgets.add(single);
    }

   Column column = Column(
      children: listCommentsWidgets,
    );

   return Expanded(
      child: Center(
        child: Container(
          width: MediaQuery.of(context).size.width * 0.90,
          child: SingleChildScrollView(
            child: column,
          ),
        ),
      ),
    );
  }

  void updateCommentaireListing(Commentaire commentaire) {
    setState(() {
      listComments.remove(commentaire);
      listCommentsWidgets.clear();
    });
  }
}

Solution

  • setState is called each time because it rebuilds your update ui. A Future can't listen to a variable change. It's a one-time response. Instead, you'll need to use a Stream if you will want to omit the setState call each time.

    For removing list item duplication

    Future _loadComments() async {
    listComments = List(); // here add empty list for 
        listComments = await MyWS()
            .getComs(widget.publication.pubId);
      }