# Riverpod Providers Quick Reference ## Essential Providers at a Glance ### Authentication ```dart // Check if user is logged in final isAuth = ref.watch(isAuthenticatedProvider); // Get current user final user = ref.watch(currentUserProvider); // Login ref.read(authProvider.notifier).login(username, password); // Logout ref.read(authProvider.notifier).logout(); // Check auth on app start ref.read(authProvider.notifier).checkAuthStatus(); // Listen to auth changes ref.listen(authProvider, (previous, next) { if (next.isAuthenticated) { // Navigate to home } if (next.error != null) { // Show error } }); ``` ### Warehouse ```dart // Load warehouses ref.read(warehouseProvider.notifier).loadWarehouses(); // Get warehouses list final warehouses = ref.watch(warehousesListProvider); // Get selected warehouse final selected = ref.watch(selectedWarehouseProvider); // Select a warehouse ref.read(warehouseProvider.notifier).selectWarehouse(warehouse); // Clear selection ref.read(warehouseProvider.notifier).clearSelection(); // Check loading state final isLoading = ref.watch(isWarehouseLoadingProvider); // Get error final error = ref.watch(warehouseErrorProvider); ``` ### Products ```dart // Load products ref.read(productsProvider.notifier).loadProducts( warehouseId, warehouseName, 'import', // or 'export' ); // Get products list final products = ref.watch(productsListProvider); // Refresh products ref.read(productsProvider.notifier).refreshProducts(); // Clear products ref.read(productsProvider.notifier).clearProducts(); // Check loading state final isLoading = ref.watch(isProductsLoadingProvider); // Get products count final count = ref.watch(productsCountProvider); // Get operation type final type = ref.watch(operationTypeProvider); // Get error final error = ref.watch(productsErrorProvider); ``` ## Widget Setup ### ConsumerWidget (Stateless) ```dart class MyPage extends ConsumerWidget { const MyPage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final data = ref.watch(someProvider); return Widget(); } } ``` ### ConsumerStatefulWidget (Stateful) ```dart class MyPage extends ConsumerStatefulWidget { const MyPage({Key? key}) : super(key: key); @override ConsumerState createState() => _MyPageState(); } class _MyPageState extends ConsumerState { @override void initState() { super.initState(); // Load data on init Future.microtask(() { ref.read(someProvider.notifier).loadData(); }); } @override Widget build(BuildContext context) { final data = ref.watch(someProvider); return Widget(); } } ``` ## Common Patterns ### Pattern 1: Display Loading State ```dart final isLoading = ref.watch(isAuthLoadingProvider); return isLoading ? CircularProgressIndicator() : YourContent(); ``` ### Pattern 2: Handle Errors ```dart final error = ref.watch(authErrorProvider); return Column( children: [ if (error != null) Text(error, style: TextStyle(color: Colors.red)), YourContent(), ], ); ``` ### Pattern 3: Conditional Navigation ```dart ref.listen(authProvider, (previous, next) { if (next.isAuthenticated) { Navigator.pushReplacementNamed(context, '/home'); } }); ``` ### Pattern 4: Pull to Refresh ```dart RefreshIndicator( onRefresh: () async { await ref.read(warehouseProvider.notifier).refresh(); }, child: ListView(...), ) ``` ### Pattern 5: Load Data on Page Open ```dart @override void initState() { super.initState(); Future.microtask(() { ref.read(warehouseProvider.notifier).loadWarehouses(); }); } ``` ## Key Methods by Feature ### Auth Methods - `login(username, password)` - Authenticate user - `logout()` - Sign out user - `checkAuthStatus()` - Check if token exists - `clearError()` - Clear error message - `reset()` - Reset to initial state ### Warehouse Methods - `loadWarehouses()` - Fetch all warehouses - `selectWarehouse(warehouse)` - Select a warehouse - `clearSelection()` - Clear selected warehouse - `refresh()` - Reload warehouses - `clearError()` - Clear error message - `reset()` - Reset to initial state ### Products Methods - `loadProducts(warehouseId, name, type)` - Fetch products - `refreshProducts()` - Reload current products - `clearProducts()` - Clear products list ## Provider Types Explained ### Provider (Read-only) ```dart // For services, repositories, use cases final myServiceProvider = Provider((ref) { return MyService(); }); // Usage final service = ref.watch(myServiceProvider); ``` ### StateNotifierProvider (Mutable State) ```dart // For managing mutable state final myStateProvider = StateNotifierProvider((ref) { return MyNotifier(); }); // Usage - watch state final state = ref.watch(myStateProvider); // Usage - call methods ref.read(myStateProvider.notifier).doSomething(); ``` ## Ref Methods ### ref.watch() - Use in `build()` method - Rebuilds widget when provider changes - Reactive to state updates ```dart final data = ref.watch(someProvider); ``` ### ref.read() - Use in event handlers, callbacks - One-time read, no rebuild - For calling methods ```dart onPressed: () { ref.read(authProvider.notifier).login(user, pass); } ``` ### ref.listen() - Use for side effects - Navigation, dialogs, snackbars - Doesn't rebuild widget ```dart ref.listen(authProvider, (previous, next) { if (next.error != null) { showDialog(...); } }); ``` ## App Initialization ```dart void main() { runApp( const ProviderScope( child: MyApp(), ), ); } class MyApp extends ConsumerStatefulWidget { @override ConsumerState createState() => _MyAppState(); } class _MyAppState extends ConsumerState { @override void initState() { super.initState(); // Check auth on app start Future.microtask(() { ref.read(authProvider.notifier).checkAuthStatus(); }); } @override Widget build(BuildContext context) { final isAuthenticated = ref.watch(isAuthenticatedProvider); return MaterialApp( home: isAuthenticated ? WarehouseSelectionPage() : LoginPage(), ); } } ``` ## Complete Example Flow ### 1. Login Page ```dart class LoginPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final isLoading = ref.watch(isAuthLoadingProvider); final error = ref.watch(authErrorProvider); ref.listen(authProvider, (previous, next) { if (next.isAuthenticated) { Navigator.pushReplacementNamed(context, '/warehouses'); } }); return Scaffold( body: Column( children: [ if (error != null) Text(error, style: TextStyle(color: Colors.red)), TextField(controller: usernameController), TextField(controller: passwordController, obscureText: true), ElevatedButton( onPressed: isLoading ? null : () { ref.read(authProvider.notifier).login( usernameController.text, passwordController.text, ); }, child: isLoading ? CircularProgressIndicator() : Text('Login'), ), ], ), ); } } ``` ### 2. Warehouse Selection Page ```dart class WarehouseSelectionPage extends ConsumerStatefulWidget { @override ConsumerState createState() => _State(); } class _State extends ConsumerState { @override void initState() { super.initState(); Future.microtask(() { ref.read(warehouseProvider.notifier).loadWarehouses(); }); } @override Widget build(BuildContext context) { final warehouses = ref.watch(warehousesListProvider); final isLoading = ref.watch(isWarehouseLoadingProvider); return Scaffold( appBar: AppBar( title: Text('Select Warehouse'), actions: [ IconButton( icon: Icon(Icons.logout), onPressed: () { ref.read(authProvider.notifier).logout(); }, ), ], ), body: isLoading ? Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: warehouses.length, itemBuilder: (context, index) { final warehouse = warehouses[index]; return ListTile( title: Text(warehouse.name), subtitle: Text(warehouse.code), onTap: () { ref.read(warehouseProvider.notifier) .selectWarehouse(warehouse); Navigator.pushNamed(context, '/operations'); }, ); }, ), ); } } ``` ### 3. Products Page ```dart class ProductsPage extends ConsumerStatefulWidget { final int warehouseId; final String warehouseName; final String operationType; const ProductsPage({ required this.warehouseId, required this.warehouseName, required this.operationType, }); @override ConsumerState createState() => _ProductsPageState(); } class _ProductsPageState extends ConsumerState { @override void initState() { super.initState(); Future.microtask(() { ref.read(productsProvider.notifier).loadProducts( widget.warehouseId, widget.warehouseName, widget.operationType, ); }); } @override Widget build(BuildContext context) { final products = ref.watch(productsListProvider); final isLoading = ref.watch(isProductsLoadingProvider); final error = ref.watch(productsErrorProvider); return Scaffold( appBar: AppBar( title: Text('${widget.warehouseName} - ${widget.operationType}'), actions: [ IconButton( icon: Icon(Icons.refresh), onPressed: () { ref.read(productsProvider.notifier).refreshProducts(); }, ), ], ), body: isLoading ? Center(child: CircularProgressIndicator()) : error != null ? Center(child: Text(error)) : RefreshIndicator( onRefresh: () async { await ref.read(productsProvider.notifier) .refreshProducts(); }, child: ListView.builder( itemCount: products.length, itemBuilder: (context, index) { final product = products[index]; return ListTile( title: Text(product.name), subtitle: Text(product.code), trailing: Text('${product.piecesInStock} pcs'), ); }, ), ), ); } } ``` ## Troubleshooting ### Provider Not Found - Ensure `ProviderScope` wraps your app in `main.dart` - Check that you're using `ConsumerWidget` or `ConsumerStatefulWidget` ### State Not Updating - Use `ref.watch()` not `ref.read()` in build method - Verify the provider is actually updating its state ### Null Value - Check if data is loaded before accessing - Use null-safe operators `?.` and `??` ### Infinite Loop - Don't call `ref.read(provider.notifier).method()` directly in build - Use `Future.microtask()` in initState or callbacks ## Cheat Sheet | Task | Code | |------|------| | Watch state | `ref.watch(provider)` | | Read once | `ref.read(provider)` | | Call method | `ref.read(provider.notifier).method()` | | Listen for changes | `ref.listen(provider, callback)` | | Get loading | `ref.watch(isXxxLoadingProvider)` | | Get error | `ref.watch(xxxErrorProvider)` | | Check auth | `ref.watch(isAuthenticatedProvider)` | | Get user | `ref.watch(currentUserProvider)` | | Get warehouses | `ref.watch(warehousesListProvider)` | | Get products | `ref.watch(productsListProvider)` |