Chuyển đến nội dung chính

Bài 6: State Management với Riverpod

Provider vs Riverpod vs Bloc. Riverpod 2.0: Provider, StateProvider, StateNotifierProvider, FutureProvider, StreamProvider. Auto-dispose, family modifier. Code generation.

💻 Lập trình — Bài 6 Bài 6: State Management với Riverpod

Flutter & Dart: Từ Cơ bản đến Nâng cao

Phần 2: Navigation & State Management

xdev.asia

1. Riverpod Setup

dependencies:
  flutter_riverpod: ^2.5.0
  riverpod_annotation: ^2.3.0

dev_dependencies:
  riverpod_generator: ^2.4.0
  build_runner: ^2.4.0
void main() {
  runApp(const ProviderScope(child: MyApp()));
}

2. Provider Types

// Simple provider
final greetingProvider = Provider<String>((ref) => 'Hello Riverpod!');

// StateProvider — simple state
final counterProvider = StateProvider<int>((ref) => 0);

// FutureProvider — async data
final productsProvider = FutureProvider<List<Product>>((ref) async {
  final repository = ref.watch(productRepositoryProvider);
  return repository.getAll();
});

// StreamProvider
final messagesProvider = StreamProvider<List<Message>>((ref) {
  return ref.watch(chatServiceProvider).messagesStream;
});

// StateNotifierProvider — complex state
class CartNotifier extends StateNotifier<List<CartItem>> {
  CartNotifier() : super([]);

  void add(Product product) {
    state = [...state, CartItem(product: product, quantity: 1)];
  }

  void remove(String productId) {
    state = state.where((item) => item.product.id != productId).toList();
  }

  double get total => state.fold(0, (sum, item) => sum + item.product.price * item.quantity);
}

final cartProvider = StateNotifierProvider<CartNotifier, List<CartItem>>((ref) {
  return CartNotifier();
});

3. Consuming Providers

class ProductListPage extends ConsumerWidget {
  const ProductListPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final asyncProducts = ref.watch(productsProvider);

    return asyncProducts.when(
      data: (products) => ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) => ProductCard(product: products[index]),
      ),
      loading: () => const CircularProgressIndicator(),
      error: (error, stack) => Text('Error: $error'),
    );
  }
}

4. Family & AutoDispose

// Family — parameterized provider
final productByIdProvider = FutureProvider.family<Product, String>((ref, id) async {
  return ref.watch(productRepositoryProvider).getById(id);
});

// AutoDispose — cleanup khi không còn listener
final searchProvider = FutureProvider.autoDispose.family<List<Product>, String>((ref, query) async {
  ref.keepAlive(); // Giữ cache cho đến khi dispose thủ công
  return ref.watch(productRepositoryProvider).search(query);
});

Bài tiếp theo: Bloc Pattern & Cubit.