Semih Yilmaz
Semih Yilmaz

Reputation: 618

SetState() not working during IconButton onPressed in Flutter

I register the post id that the user likes to the list and check whether he likes it or not.

According to the result, I want to set icon and color with IconButton in SliverAppBar, but does not work.

The basic structure of my code is like here. I don't know how I could do it differently.

class Favorite {
List<String> fav = List<String>();

bool checkFav(String id) => fav.contains(id);

addItemToFav(String id) {
    fav.add(id);
  }

deleteItemToFav(String id) {
    fav.remove(id);
  }
}

class DetailPage extends StatefulWidget {
  final Model blogModel;

  DetailPage({this.blogModel});

  @override
  _DetailPageState createState() => _DetailPageState();
}

class _DetailPageState extends State<DetailPage> {
   Favorite favorite = new Favorite();

  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;

    return SafeArea(
      child: Scaffold(
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverAppBar(
                flexibleSpace: FlexibleSpaceBar(),
                leading: IconButton(),
                actions: [
                  IconButton(
                    onPressed: () {
                      favorite.checkFav(widget.blogModel.id)
                          ? favorite.deleteItemToFav(widget.blogModel.id)
                          : favorite.addItemToFav(widget.blogModel.id);
                      print(favorite.p());
                      setState(
                            () {
                          favorite.checkFav(widget.blogModel.id)
                              ? color = Colors.red
                              : color = Colors.black;
                        },
                      );
                    },

                    icon: Icon(
                        favorite.checkFav(widget.blogModel.id)
                            ? Icons.favorite
                            : Icons.favorite_border,
                        color: color),
                  ),
                ],
              ),
            ];
          },
          body: Container(),
        ),
      ),
    );
  }
}

Upvotes: 0

Views: 1938

Answers (3)

Azarro
Azarro

Reputation: 1866

Favorite favorite = new Favorite();

The reason why it's not working is because your favorite instance is being re-created very frequently inside the widget's build() method.

When you call setState (or frequently when Flutter repaints and invokes the build() method), you're basically re-creating a new instance of Favorite.

Hence, why you lose the state of Favorites and why, when you print the list, it's empty.

So you could move the favorite object out like Salih Can showed you, that's one option.

Unfortunately, that's also not going to work the moment you add more pages or widgets to this app.

If you navigate away, you're going to lose the state of that widget (because the favorite instance was an instance member of the widget's state class, and now the widget has been garbage collected when navigating to a different widget).

This is known as ephemeral state, while you want app state (i.e. a state that persists no matter where you are in the app).

The simplest way to do this would be to use a State management solution like Provider. The linked flutter page shows a very simple way of how to set this up such that, no matter which widget you're inside of, you can be sure that your Favorites will be saved correctly.

Upvotes: 2

Salih Can
Salih Can

Reputation: 1783

You should move the following line of code above the 'build' method.

Favorite favorite = new Favorite();

It should look like this;

class _DetailPageState extends State<DetailPage> {
  Favorite favorite = new Favorite();
  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;
....

Upvotes: 0

Subair K
Subair K

Reputation: 1880

List<String> fav = List<String>(); shouldn't be inside build() method, but, inside state class.

Like

class _FavoriteWidgetState extends State<FavoriteWidget> {
 List<String> fav = List<String>();
override
  Widget build(BuildContext context) {

Upvotes: 1

Related Questions