Меня смущает, что Nested ProviderScope и все провайдеры будут удалены из памяти? И является ли использование варианта использования хорошей практикой или плохой практикой?
У меня есть idsProvider
final idsProvider = Provider((_) => List.generate(50, (i) => i));
и иметь itemIdProvider для каждого идентификатора idsProvider
final itemIdProvider = Provider.autoDispose((_) => 0);
Пользовательский интерфейс следующим образом:
class BuildListView extends ConsumerWidget {
const BuildListView({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final ids = ref.watch(idsProvider);
return ListView.builder(
itemCount: ids.length,
itemBuilder: (context, index) {
return ProviderScope(
overrides: [
itemIdProvider.overrideWithValue(ids[index]),
],
child: const BuildItem(),
);
},
);
}
}
class BuildItem extends ConsumerWidget {
const BuildItem({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final itemState = ref.watch(itemProvider);
return itemState.when(
data: (id, data) => ListTile(
title: Text("ID: $id"),
subtitle: Text(data),
),
loading: () => const CircularProgressIndicator(),
error: (error) => Text(error.toString()),
);
}
}
Затем у меня есть stateNotifierProvider для управления состоянием каждого элемента ListView:
final itemProvider = StateNotifierProvider.autoDispose<ItemNotifier, ItemState>(
(ref) => ItemNotifier(ref.watch(itemIdProvider)),
dependencies: [itemIdProvider],
);
class ItemNotifier extends StateNotifier<ItemState> {
ItemNotifier(this.id) : super(const ItemState.loading()) {
fetchData();
}
final int id;
Future<void> fetchData() async {
await Future.delayed(const Duration(seconds: 2));
if (mounted) {
state = ItemState.data(id: id, data: "Data for $id");
}
}
// A lot of methods to change the state
// ...
// ...
}
@freezed
class ItemState with _$ItemState {
const factory ItemState.data({required int id, required String data}) = Data;
const factory ItemState.loading() = Loading;
const factory ItemState.error([String? message]) = Error;
}
Я думаю, что это вполне приемлемо. Кроме того, у вас может не быть начального значения:
final itemIdProvider = Provider.autoDispose((_) => throw UnimplementedError());
Таким образом, будет видно, что значение будет реализовано позже.
О памяти. ProviderScope
— это StatefulWidget
и имеет следующие строки кода под «капотом»:
@override
void dispose() {
container.dispose();
super.dispose();
}
Так что сильно не переживайте :)
Он должен быть освобожден в нужное время. Не похоже, что у вас все еще есть какие-либо ссылки, указывающие на это.