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
},
),
],
),
);
}
}
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 ?
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.