John Joe
John Joe

Reputation: 12803

setState in futureBuilder

I want to use setState in FutureBuilder, but keeps getting

setState() or markNeedsBuild() called during build.

I have declared ratio as global variables. I would like to update the value of ratio. The ration can be only calculated once image's width and height is successfully get.

 Widget _showItem() {
    return FutureBuilder(
        future: _bloc.selectImage(),
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              return Center(
                child: CircularProgressIndicator(),
              );
              break;

            case ConnectionState.done:
              if (snapshot.hasData) {
                Image image = new Image.network(snapshot.data);
                Completer<ui.Image> completer = new Completer<ui.Image>();
                image.image.resolve(new ImageConfiguration()).addListener(
                    new ImageStreamListener((ImageInfo image, bool _) {
                  completer.complete(image.image);

                  setState(() {
                num maxHeightRatio = 300 / image.image.height;
                num maxWidthRatio = 400 / image.image.width;
                    this.ratio = maxWidthRatio.coerceAtMost(maxHeightRatio);
                  });
                }));

                return CachedNetworkImage(
                  imageUrl: snapshot.data.toString(),
                  imageBuilder: (context, imageProvider) => Container(
                    decoration: BoxDecoration(
                      image: DecorationImage(
                        image: imageProvider
                      ),
                    ),
                  ),
                  placeholder: (context, url) => CircularProgressIndicator(),
                  errorWidget: (context, url, error) => Icon(Icons.error),
                );
              } else {
                return Image.asset('assets/no_image.png');
              }
              break;

            default:
              return Text("Error");
          }
        });
  }

I understand we should not using setState in FutureBuilder, but what is the solution for this since I need to update the global variable?

Upvotes: 0

Views: 2335

Answers (1)

Sami Haddad
Sami Haddad

Reputation: 1416

It's better to move your future call to the initState method since you don't want to call your selectImage every time your widget gets built. Once you move the call outside your build method you can do all your calculations and then setState.

void initState() {
  super.initState();
  setup();
}

setup() async {
  var data = await _bloc.selectImage();
  // do calculations using data
  // setState
}

Read more on this here.

Upvotes: 1

Related Questions