DEV Community

David MM👨🏻‍💻
David MM👨🏻‍💻

Posted on

7 1

How to rebuild a ListView on Flutter using Provider async?

TL;DR: My Provider class doesn't trigger a rebuild, but I don't know what I'm doing wrong. Code provided below.

Hi,

I have a ListView.builder nested inside a Consumer.

While it creates as many MyProvider instances I have, if I delete or update an element, it does delete/update that element on the database, but it doesn't trigger a rebuild on the ListView builder, despite using notifyListeners().

This is (a simplified version of) my code:

genre_list.dart

class GenreListScreen extends StatefulWidget {
  static const routeName = '/genre-list';

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

class _GenreListScreenState extends State<GenreListScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: ...
      ),
      body: Consumer<GenreProvider>(
        builder: (context, data, index) {
          var genres = data.getGenres;

          return ListView.builder(
            itemCount: genres.length,
            itemBuilder: (context, index) {
              var genre = genres[index];
              return ListTile(
                title: Text(genre['title']),
                subtitle: IconButton(
                  icon: Icon(Icons.edit),
                  onPressed: () async {
                    try {
                      GenreProvider().updateGenre(genre['id'], 'Testing');
                    } on Exception catch (_) {
                      showSnackBar(
                        text: 'Unknown error updating the genre.',
                        color: Colors.red,
                        context: context,
                      );
                    }
                  },
                ),
              );
            },
          );
        },
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

genre_provider.dart

class GenreProvider with ChangeNotifier {
  static List<Map<String, dynamic>> _genres = [];

  Future fetchGenres() async {
    try {
      QuerySnapshot<Map<String, dynamic>> genres =
          await FirebaseFirestore.instance.collection('genres').get();

      _genres = [];
      genres.docs.forEach((genre) {
        _genres.add({'id': genre.id, 'title': genre['title']});
      });
      notifyListeners();
    } catch (e) {
      print(e);
    }
  }

  Future updateGenre(String id, String title) async {
    try {
      await FirebaseFirestore.instance
          .collection('genres')
          .doc(id)
          .update({'title': title});
      var updatedGenre = _genres.firstWhere((element) => element['id'] == id);
      updatedGenre['title'] = title;
      notifyListeners();
    } catch (e) {
      throw (e);
    }
  }

  List<Map<String, dynamic>> get getGenres {
    return _genres;
  }
}

Enter fullscreen mode Exit fullscreen mode

After a successful login, I call fetchGenres to get the data. Then, I move to GenteListScreen and I can see all the genres I have on my Database.

Clicking on the 'Edit' button, I edit the Genre on the Database (normally a Dialog with a TextFormField, but for the example it is just a fixed string), but it doesn't trigger an UI rebuild on the ListView.

Calling setState(() {}) after the function, triggers a rebuild, and everything is fine, but this call should be done automatically by the Provider package via Consumer.

So the question is: What I am missing on the code to trigger the automatically rebuild?

Heroku

The AI PaaS for deploying, managing, and scaling apps.

Heroku tackles the toil — patching and upgrading, 24/7 ops and security, build systems, failovers, and more. Stay focused on building great data-driven applications.

Get Started

Top comments (1)

Collapse
 
nikolayshtanko profile image
nikolayshtanko • Edited

Hi!, David! I'm sorry for being late :)

You should add wrapper with class "ChangeNotifierProvider" in your widget's tree.
According to this example: flutter.dev/docs/development/data-...

Your should get something like this, I think (in attach image)
dev-to-uploads.s3.amazonaws.com/up...

Learn How Clay Overcame Web Scraping Barriers

Learn How Clay Overcame Web Scraping Barriers

Clay helps customers enrich their sales pipeline with data from even the most protected sites. Discover how Clay overcame initial limitations and scaled past data extraction bottlenecks with a boost from ZenRows.

Read More

Announcing the First DEV Education Track: "Build Apps with Google AI Studio"

The moment is here! We recently announced DEV Education Tracks, our new initiative to bring you structured learning paths directly from industry experts.

Dive in and Learn

DEV is bringing Education Tracks to the community. Dismiss if you're not interested. ❤️