How to initiate ViewModel for widget(view)

Viewed 2627

So i am writing a Flutter application that utilize the MVVM architecture. I have a viewModel for every screen(widget) with ValueNotifiers and i want to initiate the viewModel for that view. Now most guides suggest a Provider approach, but why provide it when i can just normally initiate it.

Code:

class FooModel{
  final ValueNotifier<bool> _active = ValueNotifier<bool>(false);
  ValueNotifier<bool> get active => _active;

  FooModel(){_active = false;}
  doSomething(){_active=!_active}
}

What i want to do:

  @override
  Widget build(BuildContext context) {
    _viewModel = FooModel();
    return Scaffold(
      body:ValueListenableBuilder<bool>(
          valueListenable: _viewModel.active,
          builder : (context,value,_){
            if(value)return(Text("active");
            return Text("unactive");
          }

      ) 
  }

what is suggested:

  Widget build(BuildContext context) {
    return Provider<FooModel>(
      create: (_) => FooModel(),
      builder: (context, child) {
        final vm = Provider.of<FooModel>(context);
        return ValueListenableBuilder<bool>(
            valueListenable: vm.active,
            builder: (context, value) {
              if (value) return Text("active");
              return Text("unactive");
            });
      },
   );
 }

Now i understand that what i suggested creates the viewModel with every build, but that should only happen when screen is loaded thanks to ValueNotifier so its fine. I guess i just don't understand the value of providing the viewModel.

1 Answers

Flutter has a different ideology. yes, you can create Value Notifier and it's fine to do that but just thinking of the bigger picture. Check this flow you want to call an API then perform parsing and filtering on that and you have 2 views on the screen to show the same data one is to showcase the data and the other one is to interact with data and this update needs to be reflected on showcased data.

to do this what we need to do?

  1. create valuenotifier at class level that encloses both screen widgets.
  2. Call API and filter code at the class level.
  3. pass this valuenotifier to both screen widgets you may ask why right? well because one class need to update other class widgets. and that's only one way to push updates to the valuenotifier is the object itself. so you will need to pass this valuenotifier in both classes.
  4. once you do that and update has been synchronized if any setState has been called to the main widget that encloses both of this widgets then you need to do all this again.
  5. also there will be multiple instances of valuenotifier which is bad as valuenotifier is a stream and you need to close your streams once you're done with the stream so you will be needing logic to close your streams at any setState event on main widget.

What is provider exactly? and how it works? well, the provider is a change notifier class which calls setState when you call notifyDataChanged or notify method. this triggers the widget state change which is listening to that data changes. and that widget gets rebuild. This is the same logic for each and every state management library out there Bloc, ScopedBloc, or any widget like streamBuilder or ValueListenableBuilder.

In Flutter if you want to change data you just need to call setState. Just to be testable, more readable and maintainable what we will be doing is to separate logic into different files just like we do in Android or iOS and that's where this type of libraries comes into the picture to reduce our headache of typing code all over again and focusing on the main task which is the functionality of the app.

See we can create loops in different formats

for(int i=0;i<length;i++)
while(i++<length)
for(i in 0...length) 

It's up to us to provide clean and understandable code so that any other developer does not need to delete all code just because he isn't able to understand our code.

There's nothing right and wrong here in development. It's matter of what is more convenient or what makes more sense. like int i does not make sense but if we replace it with index or listIndex it will.

Also, one thing to mention is what you're doing is creating a model that is kind of the same as bloc pattern. so you're already halfway through. you just need to call state change from model check bloc and other patterns you will understand.

Related