Flutter Provider select – How do handle complex returned type like List or Map

Issue

I am trying to use flutter provider and I am having issues with context.select() when the returned type is a complex object (like Map or List) with an unchanged reference.
Even when I notify the listeners of my model, my widget won’t rebuild and I suspect it is because I’m modifying my objects in place.

Here is a simple code to reproduce

class MyModel extends ChangeNotifier {
  final list = <int>[0, 1, 2, 3, 4, 5];

  void push() {
    // Here I modify the list in place, and even when I call `notifyListeners()`, `MyWidget` won't rebuild
    list.add(list.length); 
    notifyListeners();
  }
}

class MyScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<MyModel>(
      create: (_) => MyModel(),
      child: MyWidget(),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  Widget build(BuildContext context) {
    // It is not rebuilt when the list is modified, the widget is rebuilt if I add
    // context.select<MyModel, int>((myModel) => myModel.list.length);
    // for example
    // I suspect it is because the reference of `myModel.list` didn't change
    final list = context.select<MyModel, List<int>>((myModel) => myModel.list);

    return Container(
      child: Column(
        children: [
          Text(list.join(', ')),
          TextButton(
            child: const Text('Add'),
            onPressed: () {
              context.read<MyModel>().push();
              // setState(() {}); <- I could force the rebuild here too
            },
          ),
        ],
      ),
    );
  }
}

enter image description here

When I click on the button Add, the list is updated but my widget is not rebuilt.
I could, for example, call setState(() {}) at the end of my onPressed to force a rebuild but I would rather not do that.


What is the best way to handle this ?

Solution

Your list should be immutable:

class MyModel extends ChangeNotifier {
  List<int> list = <int>[0, 1, 2, 3, 4, 5];

  void push() {
    list = [...list, list.length];
    notifyListeners();
  }
}

Otherwise, the object reference is the same and the Widget does not rebuild.

Answered By – Thierry

Answer Checked By – Jay B. (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.