Bỏ qua để đến nội dung

🌊 Riverpod

Riverpod là phiên bản cải tiến của Provider, khắc phục nhiều hạn chế:

  • Compile-time safety
  • Không cần BuildContext
  • Testable
  • Có nhiều loại providers
pubspec.yaml
dependencies:
flutter_riverpod: ^2.4.0

void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
// State đơn giản
final counterProvider = StateProvider<int>((ref) => 0);
// State từ async
final userProvider = FutureProvider<User>((ref) async {
return await api.fetchUser();
});
class CounterPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('Count: $count');
}
}

Provider Mục đích
Provider Giá trị read-only
StateProvider State primitive đơn giản
StateNotifierProvider State phức tạp với logic
FutureProvider Async data
StreamProvider Stream data
ChangeNotifierProvider Migrate từ Provider

final greetingProvider = Provider<String>((ref) {
return 'Hello, World!';
});
// Sử dụng
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final greeting = ref.watch(greetingProvider);
return Text(greeting);
}
}

final counterProvider = StateProvider<int>((ref) => 0);
class CounterPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Column(
children: [
Text('$count'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Text('+'),
),
],
);
}
}

class Todo {
final String id, title;
final bool completed;
Todo({required this.id, required this.title, this.completed = false});
Todo copyWith({String? title, bool? completed}) {
return Todo(
id: id,
title: title ?? this.title,
completed: completed ?? this.completed,
);
}
}
class TodoNotifier extends StateNotifier<List<Todo>> {
TodoNotifier() : super([]);
void add(String title) {
state = [...state, Todo(id: DateTime.now().toString(), title: title)];
}
void toggle(String id) {
state = [
for (final todo in state)
if (todo.id == id) todo.copyWith(completed: !todo.completed) else todo,
];
}
void remove(String id) {
state = state.where((t) => t.id != id).toList();
}
}
final todoProvider = StateNotifierProvider<TodoNotifier, List<Todo>>((ref) {
return TodoNotifier();
});
class TodoPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final todos = ref.watch(todoProvider);
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
final todo = todos[index];
return ListTile(
title: Text(todo.title),
leading: Checkbox(
value: todo.completed,
onChanged: (_) => ref.read(todoProvider.notifier).toggle(todo.id),
),
);
},
);
}
}

final userProvider = FutureProvider<User>((ref) async {
return await api.fetchCurrentUser();
});
class ProfilePage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsync = ref.watch(userProvider);
return userAsync.when(
data: (user) => Text('Hello, ${user.name}'),
loading: () => CircularProgressIndicator(),
error: (err, stack) => Text('Error: $err'),
);
}
}

Method Rebuild Khi nào dùng
ref.watch() Trong build()
ref.read() Không Trong callbacks
@override
Widget build(BuildContext context, WidgetRef ref) {
// watch: rebuild khi provider thay đổi
final count = ref.watch(counterProvider);
return ElevatedButton(
// read: không cần rebuild
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Text('$count'),
);
}

final userIdProvider = StateProvider<int>((ref) => 1);
final userProvider = FutureProvider<User>((ref) async {
final userId = ref.watch(userIdProvider); // Phụ thuộc vào userId
return await api.fetchUser(userId);
});
// Khi userIdProvider thay đổi, userProvider tự động refresh

  1. Khai báo providers ở global scope - top-level
  2. Dùng ref.watch trong build - ref.read trong callbacks
  3. Ưu tiên StateNotifier cho logic phức tạp
  4. Dùng .family cho parameterized providers
// Family provider
final userProvider = FutureProvider.family<User, int>((ref, userId) async {
return await api.fetchUser(userId);
});
// Sử dụng
ref.watch(userProvider(123));

Loại Khi nào dùng
Provider Constant, computed values
StateProvider Primitive state (int, bool, string)
StateNotifierProvider Complex state với logic
FutureProvider Async one-time data
StreamProvider Reactive data streams
Method Mục đích
ref.watch Lắng nghe và rebuild
ref.read Đọc một lần
ref.listen Side effects