'Flutter setState not updating a particular widget

I am using multi_select_flutter to show multi chips in my flutter project. However, am trying to add more items to the chip with data loaded from my api while the user is searching but it doesn't update the state of the multi chip widget. Here is my full code.

Even when I hot reload, it does not update itself. The only way I can manually enforce a refresh update is to re-ad the widget and reload consecutively. Any information as to why this strange behavior happens?

class MultiChoiceComponent extends StatefulWidget {
  const MultiChoiceComponent({Key key}) : super(key: key);

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

class _MultiChoiceComponentState extends State<MultiChoiceComponent> {
  ApiMethods apiMethods;

  TextEditingController searchController = TextEditingController();
  List<MultiSelectItem<dynamic>> labels = [];
  final TextEditingController textEditingController = TextEditingController();
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    apiMethods = new ApiMethods(context: context);
  }
  @override
  Widget build(BuildContext context) {
    return ListView(
      shrinkWrap: true,
      children: [
        Container(
          padding: EdgeInsets.symmetric(horizontal: 16),
          child: Text(
            'Search and select as many symptoms been experienced, it helps with a more accurate diagnosis',
            textAlign: TextAlign.start,
            style: TextStyle(
              fontSize: 14,
              height: 1.8,
              fontWeight: FontWeight.w400,
              fontFamily: 'Euclid',
              color: AppColors.grey1,
            ),
          ),
        ),
        SizedBox(
          height: 20,
        ),
        Container(
          padding: EdgeInsets.symmetric(horizontal: 16,),
          // height: maxLines * 50.0,
          child: TextField(
            controller: textEditingController,
            cursorColor: Colors.black26,
            onChanged: (val){
              if(val!=""){
                searchSymptoms(val);
              }
            },
            decoration: InputDecoration(
                filled: true,
                hintStyle: TextStyle(
                  fontSize: 14,
                  height: 1.6,
                  fontWeight: FontWeight.w400,
                  fontFamily: 'Euclid',
                  color: AppColors.grey1,
                ),
                hintText: "Search for a symptom/illness",
                fillColor: Colors.white,
                contentPadding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 14),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(12.0),
                  borderSide: BorderSide(color: AppColors.textColor.withOpacity(0.5)),
                ),
                focusedBorder: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(12.0),
                  borderSide: BorderSide(color: AppColors.textColor.withOpacity(0.5)),
                ),
                enabledBorder: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(12.0),
                  borderSide: BorderSide(color: AppColors.textColor.withOpacity(0.5)),
                )),
          ),
        ),
        MultiSelectChipField(
          scroll: false,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.transparent, width: 1.8),
          ),
          showHeader: false,
          selectedTextStyle: TextStyle(
            fontSize: 12.5,
            height: 1.8,
            fontWeight: FontWeight.w400,
            fontFamily: 'Euclid',
            color: Colors.white,
          ),
          chipShape: RoundedRectangleBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(12),
            ),
          ),
          selectedChipColor: AppColors.customGreen,
          chipColor: Colors.white,
          textStyle: TextStyle(
            fontSize: 12.5,
            height: 1.8,
            fontWeight: FontWeight.w400,
            fontFamily: 'Euclid',
            color: AppColors.textColor,
          ),
          items: labels,
          onTap: (value) {
            ///add symptoms to list
            print(value);
            selectedSymptoms = value as List<Conditions>;
          },
        ),
      ],
    );
  }
  Future<void> searchSymptoms(String searchQuery) async {
    List<dynamic> _data =  await apiMethods.searchConditions(symptomCheckerAge, searchQuery);
    conditions = Conditions.fromJsonList(_data);
    labels = conditions.map((e) => MultiSelectItem(e, e.label)).toList();
    setState(() {});
  }
}


Solution 1:[1]

Can you share the full code.. like the part where you have declared variables like labels and conditions. You need to make sure that these variables are not final firstly and that these are using the late keyword or something like List? labels. If there's any other problem kindly share the whole code of this stateful class

**EDIT

So I tried this given Chip Widget with custom data and it is working properly.. Meaning the items that i am adding on pressed are being added to the new list. Take a look and try out the few changes and see if that works for you

class _MyHomePageState extends State<MyHomePage> {
static List<Animal> _animals = [
Animal(id: 1, name: "Lion"),
Animal(id: 2, name: "Flamingo"),
Animal(id: 3, name: "Hippo"),
Animal(id: 4, name: "Horse"),
Animal(id: 5, name: "Tiger"),
Animal(id: 6, name: "Penguin"),
Animal(id: 7, name: "Spider"),
Animal(id: 8, name: "Snake"),
Animal(id: 9, name: "Bear"),
Animal(id: 10, name: "Beaver"),
Animal(id: 11, name: "Cat"),
Animal(id: 12, name: "Fish"),
Animal(id: 13, name: "Rabbit"),
];
dynamic _items = _animals
  .map((animal) => MultiSelectItem<Animal>(animal, animal.name))
  .toList();
@override
Widget build(BuildContext context) {
return new Scaffold(
  backgroundColor: Colors.white,
  appBar: new AppBar(
    title: new Text('Hello'),
  ),
  body: ListView(
    scrollDirection: Axis.vertical,
    physics: NeverScrollableScrollPhysics(),
    children: [
      Container(
        child: MultiSelectChipField(
          scroll: false,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.transparent, width: 1.8),
          ),
          showHeader: false,
          selectedTextStyle: TextStyle(
            fontSize: 12.5,
            height: 1.8,
            fontWeight: FontWeight.w400,
            color: Colors.blue,
          ),
          chipShape: RoundedRectangleBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(12),
            ),
          ),
          selectedChipColor: Colors.green,
          chipColor: Colors.yellow,
          textStyle: TextStyle(
            fontSize: 12.5,
            height: 1.8,
            fontWeight: FontWeight.w400,
            color: Colors.black,
          ),
          items: _items,
          onTap: (value) {
            ///add symptoms to list
            print(value);
          },
        ),
      ),
      ElevatedButton(
          onPressed: () {
            _items.add(MultiSelectItem<Animal>(
                Animal(id: 27, name: 'name'), 'new'));
            setState(() {});
          },
          child: Text('Add'))
    ],
  ),
  );
 }
}

 class Animal {
  final int id;
  final String name;

Animal({
required this.id,
required this.name,
});

}

Solution 2:[2]

Try this

Future<void> searchSymptoms(String searchQuery) async {
    List<dynamic> _data =  await apiMethods.searchConditions(symptomCheckerAge, searchQuery);
      conditions = Conditions.fromJsonList(_data);
      labels = conditions.map((e) => MultiSelectItem(e, e.label)).toList();
    setState(() {});
}

Solution 3:[3]

I was also struggling with hot reload of the MultiSelectChipField and the solution was to update the globalkey during reload.

Pseudo code:

  late var _multiSelectKey;
  late List<MultiSelectItem<SomeClass?>>? _items;

  @override
  void initState() {
       _items = null;
  }
    
  void reloadChip()
  {
    _multiSelectKey = GlobalKey<FormFieldState>();
    _items = getItemsFromSomeWhere();
  }

In scaffold the chip has these params

MultiSelectChipField<SomeClass?>(
                  initialValue: getSelected(),
                  key: _multiSelectKey,
                  title: const Text("Title"),
                  items: _items!,
                  onTap: (items) async { },
                  },
                ),

When function reloadChip() is called and a setState(() {}); is triggered the MultiSelectChipField will update.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Varun Kumar
Solution 3 Large