Я пытаюсь вставить разрешенный объект Riverpod StreamProvider в дерево ниже, чтобы удалить некоторые ненужные асинхронные вызовы. Если моя интерпретация документов верна, вложенный ProviderScope должен помочь с этим, но я получаю исключение времени выполнения.
Мой вариант использования: мне нужно получить доступ к объекту specs, зависящему от пользователя, высоко в дереве виджетов. Некоторые данные из этого объекта требуются для всей остальной части приложения, в том числе в качестве параметра для любой операции с БД. Объект спецификаций поступает из firebase и извлекается асинхронно с помощью StreamProvider.
Как только выполнение находится внутри виджета HomePage, я знаю, что объект спецификаций должен быть загружен и действителен, поэтому я не хочу получать его снова в качестве поставщика потока, который должен обрабатывать случаи загрузки и ошибок. Это особенно верно, когда поставщик спецификаций вводится другим комбинированным поставщикам, поскольку дополнительная нагрузка и случаи ошибок добавляют много ненужной сложности.
// Called at the root of the tree to retieve some firestore object
final specsStreamProvider = StreamProvider<Specs?>((ref) {
return ref.read(baseDatabaseProvider).currentSpecs();
});
// Called further down to provide the object that was retrieved
final specsProvider = Provider<Specs>((ref) {
throw UnimplementedError('should have been overwritten');
});
// An example of how content will be retrieved from firestore at HomePage widget and below.
// Having to use specsStreamProvider here quickly turns into a mess.
final recordStreamProvider = StreamProvider.autoDispose<List<Record>>((ref) {
final specs = ref.read<Specs>(specsProvider);
final database = ref.read(contentDatabaseProvider(specs.current!));
return database.recordsStream();
});
class SetupWidget extends ConsumerWidget {
const SetupWidget({Key? key, required this.setupBuilder, required this.homeBuilder}) : super(key: key);
final WidgetBuilder setupBuilder;
final WidgetBuilder homeBuilder;
@override
Widget build(BuildContext context, ScopedReader watch) {
final specsAsyncValue = watch(specsStreamProvider);
return specsAsyncValue.when(
data: (specs) => _data(context, specs),
loading: () => const Scaffold(/.../),
error: (e, __) => Scaffold(/.../),
));
}
Widget _data(BuildContext context, Specs? specs) {
if (specs != null) {
return ProviderScope(
// The plan here is to introduce the resolved specs into the tree below
overrides: [specsProvider.overrideWithValue(specs)],
child: homeBuilder(context),
);
}
return setupBuilder(context);
}
}
Согласно API Riverpod вложенный ProviderScope является допустимым инструментом для перезаписи поставщиков для части дерева виджетов. К сожалению, в моем случае я получаю сообщение об ошибке выполнения: «Неподдерживаемая операция: невозможно переопределить поставщиков на некорневом ProviderContainer / ProviderScope».
Я также пытался сделать specsProvider ScopedProvider, но тогда объединенный recordStreamProvider не компилируется. ('ошибка: тип аргумента' ScopedProvider 'не может быть назначен типу параметра' RootProvider ‹Object ?, Specs› '.'