I am confused that will Nested ProviderScope and all Providers be romoved from memory? And is following usecase good practice or bad practice?
I have idsProvider
final idsProvider = Provider((_) => List.generate(50, (i) => i));
and have itemIdProvider for every id of idsProvider
final itemIdProvider = Provider.autoDispose((_) => 0);
UI as follows:
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()),
);
}
}
Then I have stateNotifierProvider to manipulate the state of every item of the 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;
}
CodePudding user response:
I think it's perfectly acceptable. In addition, you may not have an initial value:
final itemIdProvider = Provider.autoDispose((_) => throw UnimplementedError());
This way it will be seen that the value will be implemented later.
About memory. ProviderScope
is a StatefulWidget
and has the following lines of code under the 'hood':
@override
void dispose() {
container.dispose();
super.dispose();
}
So you don't have to worry too much :)