Aurora Borealis
Aurora Borealis

Reputation: 39

How to setup the state management architecture for current use case?

In my flutter application, I'll be having multiple pages. Consider 2 pages for now. Both these pages have some filters that are common and can be modified from either page. Both these pages also have some additional states, values of which might depend upon the common filters state. It might also be required to make an API call to update the non-common state of the pages when the common state of the page changes. Also, suppose I modify the common filter state from one page, the non-common state of the other page should also change, as that depends on the common state as well.

Additionally, these filters would be configurable, so, I'll call a REST API to get the filter's initial value, like dates etc.

Moreover, I'd like to use the MVVM architecture to have separation of concerns between the views and the state (view model) layers.

How to structure such a setup?

I tried using Provider in the following fashion. Below mentioned is a minimal reproducable setup of the architecture I tried.

// main snippet

/// Common provider for the Module
ChangeNotifierProvider(create: (_) => CommonVm()),

/// Provider for the Page A
ChangeNotifierProxyProvider<CommonVm, PageAVm>(
   create: (context) => PageAVm(
     commonVm: context.read<CommonVm>(),
   ),
   update: (context, commonVm, pageAVm) {
     return pageAVm!..updateCommonVm(commonVm);
   },
),

// commonVM

class CommonVm extends ChangeNotifier {
  int _num = 0;
  int get count => _num;

  void increment() {
    _num++;
    notifyListeners();

  }
}

// PageA snippet

class PageAState extends State<PageA>
    with AutomaticKeepAliveClientMixin {
  /// We want this page to be alive so that init function is not called again
  /// and again, when switching tabs
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          CommonVm commonVm = context.read<CommonVm>();
          commonVm.increment();
        },
        child: Icon(Icons.add),
      ),
      body: Column(
        children: [
          Consumer<CommonVm>(
            builder: (context, value, child) {
              return Text('Number: ${value.count}');
            },
          ),
          Consumer<PageAVm>(
            builder: (context, value, child) {
              return Text('Square: ${value.square}');
            },
          ),
        ],
      ),
    );
  }

// PageA specific VM

/// View model for the Safety Home Page
class PageAVm extends ChangeNotifier {
  PageAVm({required this.safetyCommonVm});

  /// Common View Model for the module
  CommonVm commonVm;

  /// When this will get sets, something in the common has updated
  /// which should trigger an update in the other states
  void updateCommonVm(CommonVm vm) {
    commonVm = vm;
    // show loading
    // call API and update state
    _square = commonVm.count * commonVm.count;
    notifyListeners();
  }

  int _square = 0;
  int get square => _square;
}

There could a similar PageB and PageBVm in the example.

I'm not sure if this is correct. I've noticed a lot of app crashing with this setup. (App not responding popup is being shown). Please suggest, how to go approach this problem/setup. The app already uses Provider for handling some states, and I'd like to do the same. But I'd like to know, some other state-management solution would be much more applicable to my current use case.

Upvotes: 0

Views: 78

Answers (1)

Utkarsh Bhardwaj
Utkarsh Bhardwaj

Reputation: 56

you can use Bloc for this scenario.

For example, Steps for creating bloc

  1. you can create a common filter bloc for the filters across the screens
  2. you can create 2 separate bloc for each page which will help in state management of the pages and with this you can call the apis with MVVM. this setup will be helpful. leave a reply for example code if needed.

Upvotes: 1

Related Questions