Flutter Riverpod Tutorial Part 5: Riverpod Hooks

Flutter Riverpod Tutorial Part 5: Riverpod Hooks

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:

  1. hooks_riverpod

  2. flutter_hooks

flutter pub add hooks_riverpod flutter_hooks

Setup Basic Structure

  1. 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()),),
    );
  }
}

Did you find this article valuable?

Support Harish Kunchala by becoming a sponsor. Any amount is appreciated!