We are going to create a new app to use Flutter hooks. You can find the source code here: learn_flutter_hooks
If you want to know more about Flutter Hooks. You can read it here: https://harishkunchala.com/flutter-hooks-everything-to-know-about-them
Tutorial 1: Simple Counter App with Hooks Riverpod
So lets look at few examples to understand Riverpod Hooks
Setup Dependencies
Since we have create a new project we can add the following dependencies:
hooks_riverpod
flutter_hooks
flutter pub add hooks_riverpod flutter_hooks
Setup Basic Structure
- Main Entry Point:
Let's setup the main.dart
to accept Riverpod
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'pages/home_page.dart';
void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
home: const HomePage(),
);
}
}
Let's check it out
Tutorial 1:
// 1. Create a StateProvider to hold the counter value:
final localCounterProvider = StateProvider<int>((ref) => 0);
class CounterHookPage extends HookConsumerWidget {
const CounterHookPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// 2. Access and display the counter value
final count = ref.watch(localCounterProvider);
return Scaffold(
appBar: AppBar(
title: const Text('Hooks 1: CounterProvider'),
),
body: Center(
child: Text(
'Count: $count',
style: const TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 3. Update the Counter value
ref.read(localCounterProvider.notifier).state++;
},
child: const Icon(Icons.add),
),
);
}
}
Tutorial 2
class FavoriteNotifier extends StateNotifier<bool> {
FavoriteNotifier() : super(true);
void toggleFavorite() => state = !state;
}
final favoriteStateNotifierProvider =
StateNotifierProvider<FavoriteNotifier, bool>((ref) => FavoriteNotifier());
class AnimationHooksPage extends HookConsumerWidget {
const AnimationHooksPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final isFavorite = ref.watch(favoriteStateNotifierProvider);
final animationController = useState(
useAnimationController(duration: const Duration(milliseconds: 300)));
useEffect(() {
if (isFavorite) {
animationController.value.forward();
} else {
animationController.value.reverse();
}
return null;
}, [isFavorite]);
return Scaffold(
appBar: AppBar(
title: const Text('Favorite Button'),
),
body: Center(
child: ScaleTransition(
scale: animationController.value,
child: IconButton(
iconSize: 100,
icon: Icon(
isFavorite ? Icons.favorite : Icons.favorite_border,
color: isFavorite ? Colors.red : Colors.black,
),
onPressed: () {
ref.read(favoriteStateNotifierProvider.notifier).toggleFavorite();
},
),
),
),
);
}
}
Tutorial 3:
final userDataProvider = FutureProvider<Map<String, dynamic>>((ref) async {
final apiResponse =
await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users/1'));
if (apiResponse.statusCode == 200) {
return jsonDecode(apiResponse.body);
} else {
throw Exception('Failed to load user');
}
});
class FutureProviderHooksPage extends HookConsumerWidget {
const FutureProviderHooksPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsyncData = ref.watch(userDataProvider);
final animationController = useState(useAnimationController(duration: const Duration(milliseconds: 500)));
useEffect((){
userAsyncData.whenData((data){
animationController.value.forward();
}
);
return null;
},[userAsyncData]);
return Scaffold(
appBar: AppBar(title: const Text('Getting the User'),
),
body: Center(child: userAsyncData.when(data: (jsonUser) => ScaleTransition(
scale: animationController.value,
child: ListTile(title: Text('${jsonUser['name']}'),
subtitle: Text('${jsonUser['email']}'),),
), error: (error, stackTrace) => Text('Error : ${error.toString()}'), loading: () => const CircularProgressIndicator()),),
);
}
}