In modern mobile app development, state management is the backbone of the app. Especially in the Flutter ecosystem, choosing the right state management approach directly affects the success of the application. In this article, we will examine in detail why we prefer Riverpod and its advantages over Provider.
What is Riverpod?
Riverpod is a redesign of the Provider package proposed by Google, the creator of Flutter. It was developed to solve some of the fundamental problems faced by Provider. Even the name is an anagram of the word Provider!
Key Advantages of Riverpod
Provider vs Riverpod: Key Differences
Limitations of the Provider
dart
// Typical problem with Provider
final userProvider = Provider((ref) {
// Compile error - no context available
return Provider.of(context).user;
});
Riverpod’s Solution
dart
// Solution with Riverpod
final authServiceProvider = Provider((ref) => AuthService());
final userProvider = Provider((ref) {
// Runs smoothly!
return ref.watch(authServiceProvider).user;
});
State Management Best Practices with Riverpod
1. State Immutability
The immutability of the state increases the predictability of the application and reduces errors:
dart
@immutable
class GameState {
final List> board;
final int score;
final bool isComplete;
const GameState({
required this.board,
required this.score,
this.isComplete = false,
});
GameState copyWith({
List>? board,
int? score,
bool? isComplete,
}) {
return GameState(
board: board ?? this.board,
score: score ?? this.score,
isComplete: isComplete ?? this.isComplete,
);
}
}
2. Use of State Notifiers
dart
final gameStateNotifierProvider = StateNotifierProvider((ref) {
return GameStateNotifier();
});
class GameStateNotifier extends StateNotifier {
GameStateNotifier() : super(GameState(
board: List.generate(9, (_) => List.filled(9, 0)),
score: 0,
));
void updateCell(int row, int col, int value) {
final newBoard = state.board.map((list) => [...list]).toList();
newBoard[row][col] = value;
state = state.copyWith(
board: newBoard,
score: calculateScore(newBoard),
);
}
// Oyun mantığı methodları
void startNewGame() {
state = GameState(
board: generateNewBoard(),
score: 0,
);
}
void checkCompletion() {
final isComplete = validateBoard(state.board);
if (isComplete) {
state = state.copyWith(isComplete: true);
}
}
}
Performance Optimization
Important techniques for performance optimization with Riverpod:
1. Use of Select
dart
final todoListProvider = StateNotifierProvider>((ref) => TodoList());
// Listen only to completed todos
final completedTodosCount = todoListProvider.select(
(todos) => todos.where((todo) => todo.completed).length,
);
2. Family Modifier
dart
final todoProvider = FutureProvider.family((ref, id) async {
return await ref.read(todoRepositoryProvider).fetchTodo(id);
});
// Use of
final todo = ref.watch(todoProvider('123'));
Extended Use with Riverpod Hooks
You can get a stronger structure with the combination of Flutter Hooks and Riverpod:
dart
class GameScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final gameState = ref.watch(gameStateNotifierProvider);
final timer = useTimer(const Duration(seconds: 1), repeating: true);
useEffect(() {
timer.start();
return timer.stop;
}, []);
return Column(
children: [
Text('Duration: ${timer.tick}'),
// Oyun tahtası widget'ları
],
);
}
}
Testing
Riverpod’s testability is very strong:
dart
void main() {
test('GameState updates correctly', () {
final container = ProviderContainer();
addTearDown(container.dispose);
final notifier = container.read(gameStateNotifierProvider.notifier);
notifier.updateCell(0, 0, 5);
expect(
container.read(gameStateNotifierProvider).board[0][0],
equals(5),
);
});
}
Result
Riverpod is a powerful and reliable state management solution for modern Flutter applications. It stands out with its advantages such as compile-time safety, easy testability and clean code structure. These features are the main reason why we prefer Riverpod in our Sudoku application at Chipode.





