So I am trying to add filters to my calorie tracking app and I encountered this problem. I try to individually change the value of different booleans (ex.: vegan, keto ...) and it changes in the widget that I change them in (Item), but not in the parent (CategoryGrid) widget. Although, the value of _isSelected changes as it is supposed to, the value of categoryType is not reflected in the parent (CategoryGrid) widget. This is the code:

class CategoryGrid extends StatefulWidget {
  Recipe recipe;
  CategoryGrid(this.recipe);

  @override
  State<CategoryGrid> createState() => _CategoryGridState();
}

class _CategoryGridState extends State<CategoryGrid> {
  bool isVegan = false;
  bool isVegetarian = false;
  bool isKeto = false;
  bool isLowFat = false;
  bool isLowCarbs = false;
  bool isLowCalories = false;

  @override
  void setState(VoidCallback fn) {
    isVegan = widget.recipe.isVegan;
    isVegetarian = widget.recipe.isVegetarian;
    isKeto = widget.recipe.isKeto;
    isLowFat = widget.recipe.isLowFat;
    isLowCarbs = widget.recipe.isLowCarbs;
    isLowCalories = widget.recipe.isLowCalories;
    super.setState(fn);
  }

  void changeValue(bool value) {
    setState(() {
      value = !value;
    });
    print(value);
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      ...
                Item('Vegan', isVegan, changeValue),
                Item('Vegetarian', isVegetarian, changeValue),
                Item('Low-fat', isLowFat, changeValue),
                Item('Low-carbs', isLowCarbs, changeValue),
                Item('Low-calories', isLowCalories, changeValue),
                Item('Keto', isKeto, changeValue),
             ...
          ),
          ElevatedButton(
            ...
            onPressed: () {
              widget.recipe = Recipe(
                id: widget.recipe.id,
                title: widget.recipe.title,
                ingredients: widget.recipe.ingredients,
                steps: widget.recipe.steps,
                servings: widget.recipe.servings,
                description: widget.recipe.id,
                creatorId: widget.recipe.id,
                p: widget.recipe.p,
                c: widget.recipe.c,
                f: widget.recipe.f,
                kcal: widget.recipe.kcal,
                imageUrl: widget.recipe.imageUrl,
                isVegan: isVegan,
                isKeto: isKeto,
                isLowCalories: isLowCalories,
                isLowCarbs: isLowCarbs,
                isLowFat: isLowFat,
                isVegetarian: isVegetarian,
              );
              print(widget.recipe.isKeto);
              print(widget.recipe.isVegan);
              Navigator.of(context).pop(widget.recipe);
            },
            child: const Text('Save filters'),
          ...
  }
}

// The individual item widget

class Item extends StatefulWidget {
  final String data;
  bool categoryType;
  Function changeValue;
  Item(this.data, this.categoryType, this.changeValue);

  @override
  State<Item> createState() => _ItemState();
}

class _ItemState extends State<Item> {
  bool _isSelected = false;
  @override
  Widget build(BuildContext context) {
    return ElevatedButton.icon(
      ...
      onPressed: () {
        setState(() {
          _isSelected = !_isSelected;
          widget.categoryType = _isSelected;
        }); 
        widget.changeValue(widget.categoryType);
      },
      ...
    );
  }
}


Solution 1: ABV

In your case it was not working because, In below method you are updating the value to true/false

 onPressed: () {
        setState(() {
          _isSelected = !_isSelected;
          widget.categoryType = _isSelected;
        }); 
        widget.changeValue(widget.categoryType);
      },

And in below method you are again updating it

 void changeValue(bool value) {
    setState(() {
      value = !value;
    });
    print(value);
  }

So you have two choice, 1. Stop updating value in child 2. Stop updating value in parent. I believe you should stop updating value in child and remove _isSelected variable from item widget.

class Item extends StatefulWidget {
  final String data;
  bool categoryType;
  Function changeValue;
  Item(this.data, this.categoryType, this.changeValue);

  @override
  State<Item> createState() => _ItemState();
}

class _ItemState extends State<Item> {

  @override
  Widget build(BuildContext context) {
    return ElevatedButton.icon(

/// Use the widget.categoryType to make this button selected.
...
      onPressed: () {

        widget.changeValue(widget.categoryType);
      },
      ...
    );
  }
}


Solution 2: Rohit Suthar

There are two changes that you have to do:

  1. In your changeValue function you are updating the value of function parameter value, not your bool variables like isVegan, isVegetarian, etc
  2. You are passing isVegan, isVegetarian value to your Item widget. Anyway the value which you are setting to categoryType in your Item widget will not update the parent variables because dart does not have reference parameters. Arguments are passed as values.

You have to set the value to your isVegan, isVegetarian, ... variables by passing a separate function callback like this.

Item('Vegan', isVegan, (value) {isVegan = value; }),
Item('Vegetarian', isVegetarian, (value) {isVegetarian = value; }),
... // so on for all your items