Consumer works, Selector doesn't, why?

Issue

Here’s a flutter widget with provider:

class FixtureList extends StatelessWidget {
  const FixtureList({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Consumer<AppState>(
      builder: (context, appState, _) => ListView(
        children: appState.fixtures.isNotEmpty
            ? appState.fixtures
                .map((e) => FixtureListItem(
                      fixtureId: e.name,
                    ))
                .toList()
            : [],
      ),
    );
  }
}

Works great, but I’m using only appState.fixtures, so why not listen only to that part with a Selector, like so:

  @override
  Widget build(BuildContext context) {
    return Selector<AppState, List<Fixture>>(
      selector: (context, appState) => appState.fixtures,
      builder: (context, fixtures, _) => ListView(
        children: fixtures.isNotEmpty
            ? fixtures
                .map((e) => FixtureListItem(
                      fixtureId: e.name,
                    ))
                .toList()
            : [],
      ),
    );
  }

This doesn’t work, the ListWiew is not re-rendered when notifyListeners is called in AppState.

Any idea what’s wrong?

Solution

You mentioned in comments that you’re just calling add on your fixtures list. This means that you’re actually returning the same List<Fixture> object every time. The Selector then compares two references to the same object, concludes that they’re the same, and doesn’t rebuild your widget.

To make Selector work as intended, you will need to create a new List<Fixture> instance whenever you want to modify its contents:

fixtures = [...fixtures, fixtureToAdd];
notifyListeners();

Answered By – Nitrodon

Answer Checked By – Mildred Charles (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *