Search code examples
flutterriverpod

Flutter riverpod provider not displaying correct data


I have a Riverpod provider created as such:

@riverpod
class SelectedEntities extends _$SelectedEntities {
  @override
  Set<FileOfInterest> build(FileType type) {
    return {};
  }

  void add(FileOfInterest entity) {
    if (!state.contains(entity)) {
      state = { ...state, entity};
    }
  }
}

I can add to the provider as expected using ref.read, if I do so, the ProviderObserver shows the output as I would expect:

flutter: selectedEntitiesProvider(PreviewGrid): {picture.jpg}

I have a PreviewGrid which uses ref.watch to look for the data from the provider. If the PreviewGrid has never been opened (I need to click on a button to show it) and I then open it, the provider is showing as empty:

flutter: PreviewGrid.build(): {}

(from a debugPrint in the build function of the PreviewGrid). If the PreviewGrid is already open though, when I select the file, everything shows up as expected:

flutter: selectedEntitiesProvider(PreviewGrid): {picture.jpg} // ProviderObserver output
flutter: PreviewGrid.build(): {picture.jpg}

What am I missing, please?

Given Riverpod providers operate outside the Widget tree, not sure why I am getting disoarate results based on Visibility...


Solution

  • As @Randal Schwartz correctly pointed out:

    Your generated provider is defaulting to autodispose. If you're not holding a ref.watch on the provider somewhere, it will reset.

    There are two solutions to this dilemma:

    1. Use the @Riverpod annotation and in it the keepAlive parameter, then your code will look like this:
    @Riverpod(keepAlive: true)
    class SelectedEntities extends _$SelectedEntities {...}
    

    This will allow your state to be created the first time selectedEntitiesProvider is accessed and then held even if the provider is no longer watching. Some kind of state caching!

    1. In the widget above your PreviewGrid on the widget tree, add a listener to the build or initState method. And your provider will live on as long as it's bugged by this widget:
    @override
      Widget build(BuildContext context) {
        ref.listen(selectedEntitiesProvider, (_, __) {});
        return ...;
      }