fill
This commit is contained in:
508
lib/core/di/QUICK_REFERENCE.md
Normal file
508
lib/core/di/QUICK_REFERENCE.md
Normal file
@@ -0,0 +1,508 @@
|
||||
# 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<AuthState>(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<MyPage> createState() => _MyPageState();
|
||||
}
|
||||
|
||||
class _MyPageState extends ConsumerState<MyPage> {
|
||||
@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<AuthState>(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<MyService>((ref) {
|
||||
return MyService();
|
||||
});
|
||||
|
||||
// Usage
|
||||
final service = ref.watch(myServiceProvider);
|
||||
```
|
||||
|
||||
### StateNotifierProvider (Mutable State)
|
||||
```dart
|
||||
// For managing mutable state
|
||||
final myStateProvider = StateNotifierProvider<MyNotifier, MyState>((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<AuthState>(authProvider, (previous, next) {
|
||||
if (next.error != null) {
|
||||
showDialog(...);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## App Initialization
|
||||
|
||||
```dart
|
||||
void main() {
|
||||
runApp(
|
||||
const ProviderScope(
|
||||
child: MyApp(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class MyApp extends ConsumerStatefulWidget {
|
||||
@override
|
||||
ConsumerState<MyApp> createState() => _MyAppState();
|
||||
}
|
||||
|
||||
class _MyAppState extends ConsumerState<MyApp> {
|
||||
@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<AuthState>(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<WarehouseSelectionPage> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends ConsumerState<WarehouseSelectionPage> {
|
||||
@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<ProductsPage> createState() => _ProductsPageState();
|
||||
}
|
||||
|
||||
class _ProductsPageState extends ConsumerState<ProductsPage> {
|
||||
@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)` |
|
||||
Reference in New Issue
Block a user