Debug School

rakesh kumar
rakesh kumar

Posted on • Updated on

Explain the difference between different kind state management lifecycle in Flutter

Provider
Riverpod
Bloc (Business Logic Component)
Redux
MobX

The lifecycle methods and patterns of various state management solutions in Flutter is crucial for effectively managing state in your application. Here’s a comparison of some popular state management approaches in Flutter, highlighting their lifecycle methods and differences:

Provider

Lifecycle Methods:

ChangeNotifier: A class that provides change notification to its listeners.
notifyListeners(): Notifies all the listeners about changes.
initState in StatefulWidget: Initialize the provider.
dispose in StatefulWidget: Dispose of the provider.
Usage:

  • Providers are created using ChangeNotifierProvider, Provider, Consumer, etc.
  • Suitable for managing simple to moderately complex state . Example:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<CounterModel>(context);

    return Scaffold(
      appBar: AppBar(title: Text('Provider Example')),
      body: Center(
        child: Text('Count: ${counter.count}'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counter.increment(),
        child: Icon(Icons.add),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Riverpod

Lifecycle Methods:

Similar to Provider, but with a different API.
Provider: The simplest provider type.
StateNotifierProvider: For more complex state management using StateNotifier.
ProviderScope: Used to provide Riverpod providers to the widget tree.
Usage:

Uses ProviderScope, Provider, StateNotifierProvider, etc.
Provides compile-time safety and improved performance over Provider.
Example:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);

  void increment() => state++;
}

final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
  return CounterNotifier();
});

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, ScopedReader watch) {
    final counter = watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: Text('Riverpod Example')),
      body: Center(
        child: Text('Count: $counter'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read(counterProvider.notifier).increment(),
        child: Icon(Icons.add),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Bloc (Business Logic Component) Lifecycle Methods:

Bloc: A class that manages state using Streams.
Streams: For state updates.
Sink: For events that cause state changes.
BlocProvider: Provides the bloc to the widget tree.
dispose(): Close streams to avoid memory leaks.
Usage:

Ideal for managing complex state with clear separation of business logic.
Uses events and states to manage state transitions.
Example:

dart
Copy code
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

enum CounterEvent { increment }

class CounterBloc extends Bloc {
CounterBloc() : super(0);

@override
Stream mapEventToState(CounterEvent event) async* {
if (event == CounterEvent.increment) {
yield state + 1;
}
}
}

void main() {
runApp(
BlocProvider(
create: (context) => CounterBloc(),
child: MyApp(),
),
);
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterScreen(),
);
}
}

class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counterBloc = BlocProvider.of(context);

return Scaffold(
  appBar: AppBar(title: Text('Bloc Example')),
  body: Center(
    child: BlocBuilder<CounterBloc, int>(
      builder: (context, count) {
        return Text('Count: $count');
      },
    ),
  ),
  floatingActionButton: FloatingActionButton(
    onPressed: () => counterBloc.add(CounterEvent.increment),
    child: Icon(Icons.add),
  ),
);
Enter fullscreen mode Exit fullscreen mode

}
}

Redux

Lifecycle Methods:

Store: Holds the application state.
Reducer: Pure function to handle actions and return new state.
Middleware: Intercepts actions to perform side effects.
StoreProvider: Provides the store to the widget tree.
dispose(): Clean up any resources if necessary.
Usage:

Suitable for managing global state in a predictable way.
Actions, reducers, and middleware define the state transitions and side effects.
Example:

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';

class AppState {
  final int counter;

  AppState(this.counter);
}

enum Actions { Increment }

AppState counterReducer(AppState state, dynamic action) {
  if (action == Actions.Increment) {
    return AppState(state.counter + 1);
  }
  return state;
}

void main() {
  final store = Store<AppState>(
    counterReducer,
    initialState: AppState(0),
  );

  runApp(MyApp(store));
}

class MyApp extends StatelessWidget {
  final Store<AppState> store;

  MyApp(this.store);

  @override
  Widget build(BuildContext context) {
    return StoreProvider<AppState>(
      store: store,
      child: MaterialApp(
        home: CounterScreen(),
      ),
    );
  }
}

class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Redux Example')),
      body: Center(
        child: StoreConnector<AppState, int>(
          converter: (store) => store.state.counter,
          builder: (context, count) {
            return Text('Count: $count');
          },
        ),
      ),
      floatingActionButton: StoreConnector<AppState, VoidCallback>(
        converter: (store) {
          return () => store.dispatch(Actions.Increment);
        },
        builder: (context, callback) {
          return FloatingActionButton(
            onPressed: callback,
            child: Icon(Icons.add),
          );
        },
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

MobX

Lifecycle Methods:

Observable: Reactive state that can be observed.
Action: Modifies observable state.
Reaction: Observes changes and reacts to them.
Observer: Rebuilds the UI when observable state changes.
dispose(): Clean up resources and reactions.
Usage:

Best for fine-grained reactivity and managing complex state.
Uses observables, actions, and reactions for state management.
Example:

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:provider/provider.dart';

class Counter = _Counter with _$Counter;

abstract class _Counter with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }

  @action
  void decrement() {
    value--;
  }
}

void main() {
  runApp(
    Provider<Counter>(
      create: (_) => Counter(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<Counter>(context);

    return Scaffold(
      appBar: AppBar(title: Text('MobX Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Observer(
              builder: (_) => Text('Count: ${counter.value}'),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                ElevatedButton(
                  onPressed: counter.increment,
                  child: Text('Increment'),
                ),
                SizedBox(width: 20),
                ElevatedButton(
                  onPressed: counter.decrement,
                  child: Text('Decrement'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Image description

Image description

Image description

Comparison of different state management techniques

When choosing a state management technique for your project, it’s important to consider the unique characteristics of each technique and how they fit with your project requirements. Here is a comparison of the different state management techniques:

Image description

Image description

Reference

Top comments (0)