Skip to content

Managing state in flutter using riverpod(various examples)

Notifications You must be signed in to change notification settings

NSM722/State-in-Flutter

Repository files navigation

Flutter State Management

// starter template
class HomePage extends ConsumerWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Home Page',
        ),
      ),
      body: const Center(
        child: Text(
          '....',
        ),
      ),
    );
  }
}
// Getting enum values
enum Color { red, green, blue }

void main() {
  List<Color> colors = Color.values;
  print(colors);

  // Output: [Color.red, Color.green, Color.blue]

  colors.forEach((value) {
    List<String> parts = value.toString().split('.');
    String first = parts.first;
    String last = parts.last;
    print('First: $first, Last: $last');
  });
}

Riverpod

Riverpod is a simple way to access your state and manage your state in Flutter.

It is a Provider replacement that is more powerful and easier to use.

Type aliases

A type alias is a way to give a type a different name making the code more readable.

// Type alias
typedef BasketballScore = int;

// Using the type alias
BasketballScore score = 10;

Provider

A provider is a global object that can be accessed anywhere in the app and provides a value to a widget.

Notifier class concept

A notifier class is a class that has a state and can notify listeners when the state changes. This class is implicitly generated by Riverpod when one creates a StateProvider or StateNotifierProvider.

StateNotifier

StateNotifier is a class that has a state and can notify listeners when the state changes.

One can read the state and modify the state.

StateNotifierProvider

This is a provider that provides a StateNotifier to the widget tree.

ConsumerWidget

This is a stateless widget that listens to changes to a provider and rebuilds when the provider changes.

This means the UI will update when the provider changes.

ref.watch() - Listens to changes in a provider and rebuilds the widget when the provider changes.

ref.read() - Reads the current value of a provider without listening to changes.

StateProvider

This is a simple provider that provides a value that can be read and modified.

When you create a state provider using StateProvider, Riverpod automatically generates a corresponding notifier class behind the scenes. This notifier class is responsible for updating the state and notifying any listeners when the state changes

FutureProvider

This provider is used to asynchronously provide data to the widget tree, commonly employed for fetching data from APIs or databases.

It has three states:

  • loading - Indicates the future is still loading and data has not been fetched yet
  • error - Signifies an error in the future during fetching. The error message and stack trace are passed as arguments
  • data - When the future has completed successfully

One can use the when method to access the result of the future. This method allows one to handle the three states of the future.

Depending on the state of the future, the appropriate function is executed, allowing one to handle each state accordingly

// Example code for FutureProvider
class UserData {
  final String name;
  final int age;

  UserData(this.name, this.age);
}

final userDataProvider = FutureProvider<UserData>((ref) async {
  // Simulating an asynchronous operation
  await Future.delayed(Duration(seconds: 2));

  // Fetching user data from an API or database
  final userData = await fetchUserData();

  return userData;
});

class HomePage extends ConsumerWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home Page'),
      ),
      body: Center(
        child: ref.watch(userDataProvider).when(
          loading: () => CircularProgressIndicator(),
          error: (error, stackTrace) => Text('Error: $error'),
          data: (userData) => Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('Name: ${userData.name}'),
              Text('Age: ${userData.age}'),
            ],
          ),
        ),
      ),
    );
  }
}

StreamProvider

Streams represent a sequence of asynchronous events over time

StreamProvider is a type of provider that provides a stream of data to your Flutter widgets. It allows you to access and listen to the data stream within your application.

One can use a stream provider to provide streams of data from various sources, such as databases, APIs, or local files, and then use these streams to update your Flutter UI in real-time based on the changes in the data.

// Example code for StreamProvider
final counterStreamProvider = StreamProvider<int>((ref) async* {
  int counter = 0;
  while (true) {
    await Future.delayed(Duration(seconds: 1));
    yield counter++;
  }
});

ChangeNotifierProvider

Thia is a type of provider that provides a ChangeNotifier to your Flutter widgets. It allows you to access and listen to the ChangeNotifier within your application.

The widgets consuming a ChangeNotifier can only listen to the changes but will not be aware of the changes in the state i.e which part of the state object has changed.

The widget is only notified that the state has changed and it needs to rebuild.

When using the ChangeNotifierProvider, one has to manually call the notifyListeners() method to notify the listeners that the state has changed.

StateNotifierProvider

This is a type of provider that provides a StateNotifier to your Flutter widgets.

It allows you to access and listen to the changes in the state and modify the state.

It's common for a StateNotifier to be used with a StateNotifierProvider to provide the StateNotifier to the widget tree.

It also encapsulates the state object, the copyWith method to update the state and additional methods for mutating the state.