Search code examples
androidflutterdartriverpod

Flutter: How to make an object accessible to other widgets without passing


I am building an application focusing on reminders. From the list of reminders present on the homepage, a reminderSection widget is shown. The reminderSection has an attribute thisReminder. I want thisReminder to be accessible to all of the descendant widgets of thisReminder. So that they can use thisReminder and I don't have to pass it around.

What I've done is use Riverpod. I wrapped myApp with ProviderScope and defined the provider in the initState of reminderSection like this:

final thisReminderProvider = Provider<Reminder>((ref) => widget.thisReminder);

And I want to use it in another widget, for example, reminderFormSection which is just where the title and dateTime of the reminder is set. I did the necessary changes to the class definition and tried accessing the provider in the initState like this:

class ReminderFormSection extends ConsumerStatefulWidget {

  const ReminderFormSection({
    super.key,
  });

  @override
  ConsumerState<ReminderFormSection> createState() => _ReminderFormSectionState();
}

class _ReminderFormSectionState extends ConsumerState<ReminderFormSection> {
  late Reminder thisReminder;

  @override
  void initState() {

    thisReminder = ref.read(thisReminderProvider);
    super.initState();
  }
}

The problem is that I'm getting the error that thisReminderProvider is undefined. I think I need to define the provider outside the class and the reminderSection file's path to the reminderFormSection file. But how do I define the provider outside the class if the object I want to provide is a class attribute?


Solution

  • It seems what you are looking for it to be able to change the reminder that is selected from one part of your code, and be able to get the current value in another widget (ReminderFormSection).

    Providers shall always be global variables. In your case, since you want to be able to change the state you shall use a "Notifier":

    final reminderProvider = NotifierProvider<ReminderNotifier, Reminder?>(ReminderNotifier.new);
    
    final class ReminderNotifier extends Notifier<Reminder?> {
      @override
      Reminder? build() {
        return null;
      }
    
      /// Function used to change the selected reminder, which will notify any widgets watching the Provider.
      void select(final Reminder reminder) {
        state = reminder;
      }
    }
    

    Wherever you are selecting the reminder, use the notifier of the provider:

    final reminderNotifier = ref.read(reminderProvider.notifier);
    // ...
    reminderNotifier.select(reminder);
    

    Then, in widgets where you want to access to the currently selected reminder, you shall watch the provided value.

    class ReminderFormSection extends ConsumerWidget {
    
      @override
      Widget build(BuildContext context, WdigetRef ref) {
        final Reminder? reminder = ref.watch(reminderProvider);