Hello I'm having a lot of trouble understanding how to use providers when fetching data.
Lets say I have an http service that fetches the data and updates a list:
my_provider.dart:
class InventoryProvider extends ChangeNotifier {
List<Item> _items = [];
List<Item> get items => List.unmodifiable(_items);
Future<List<Item>> fetchAllItems() async {
_items = await ItemService().fetchAllItems();
notifyListeners();
return items;
}
}
Now I want to build my list. The only solution I have found to work is the following:
my_screen:
class InventoryScreen extends StatefulWidget {
static const routeName = '/';
const InventoryScreen({
super.key,
});
@override
State<InventoryScreen> createState() => _InventoryScreenState();
}
class _InventoryScreenState extends State<InventoryScreen> {
final List<Item> _items = [];
bool _isLoading = false;
String _errorMessage = '';
/// Fetch items
@override
void initState() {
super.initState();
_isLoading = true;
final itemProvider = Provider.of<InventoryProvider>(context, listen: false);
itemProvider.fetchAllItems().then((posts) {
setState(() {
for (Item item in posts) {
_items.add(item);
}
_isLoading = false;
});
}).catchError((e) {
setState(() {
_errorMessage = e.message;
_isLoading = false;
});
});
}
...
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
...
body: _isLoading
? const Center(child: CircularProgressIndicator())
: _errorMessage.isNotEmpty
? Center(child: Text(_errorMessage))
: _items.isEmpty
? const Center(child: Text('You do not have any item yet.'))
: ListView.builder(
itemCount: _items.length,
itemBuilder: (BuildContext context, int index) {
final item = _items[index];
return ListTile(
So this works for the first fetch as:
- It displays something (the progress indicator) while the data is being fetched.
- I obtain all the data from the provider.
It does not work for:
- Refreshing the list in case the provider changes (For example, if when you access to the item details you can delete one item of the list and then pop back to the list).
What I have tried:
- Remove the
listen: False
. Triggers:
Exception has occurred.
FlutterError (dependOnInheritedWidgetOfExactType<_InheritedProviderScope<InventoryProvider?>>() or dependOnInheritedElement() was called before _InventoryScreenState.initState() completed.
When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.
Typically references to inherited widgets should occur in widget build() methods. Alternatively, initialization based on inherited widgets can be placed in the didChangeDependencies method, which is called after initState and whenever the dependencies change thereafter.)
- Change the
initState
fordidChangeDependencies
with listen false: Enters an infinite loop of requests.
Any help on how should this be done?