Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Scoped Model to maintain app state in flutter

I need help creating the architecture for my application. I am using Flutter and scoped_model to maintain state.

It's an application that has a login, that displays news in one part of the application, and shows a photo gallery among others. I would like to split this entire thing into separate Models. LoginModel that holds Login state (like username, token, name etc.). NewsModel that contains news retrieved from the API. GalleryModel to hold names of photos etc. I am not sure if this is the best practice to maintain state using scoped_model.

For eg, what If a text box depends on both LoginModel and NewsModel? I am not sure, but I guess it's not possible to retrieve state from two separate models. Also, the main reason I am maintaining separate Models to hold state is that I don't want the Login part of the app to get refreshed when I bring news. I guess that's how it goes when I put the entire state in a single model.

like image 498
Pongal Avatar asked Jun 25 '18 08:06

Pongal


1 Answers

The scoped_model library is designed to work with multiple models in play at the same time. That's part of the reason that ScopedModel and ScopedModelDescendant are generics and have a type parameter. You can define multiple models near the top of your Widget tree using ScopedModel<LoginModel> and ScopedModel<NewsModel> and then consume those models lower in the tree using ScopedModelDescendant<LoginModel> and ScopedModelDescendant<NewsModel>. The descendants will go looking for the appropriate model based on their type parameter.

I knocked together a quick example. Here are the models:

class ModelA extends Model {
  int count = 1;
  void inc() {
    count++;
    notifyListeners();
  }
}

class ModelB extends Model {
  int count = 1;
  void inc() {
    count++;
    notifyListeners();
  }
}

And here's what I'm displaying in the app:

ScopedModel<ModelA>(
  model: ModelA(),
  child: ScopedModel<ModelB>(
    model: ModelB(),
    child: ScopedModelDescendant<ModelA>(
      builder: (_, __, a) => ScopedModelDescendant<ModelB>(
        builder: (_, __, b) {
          return Center(
            child: Column(
              children: [
                GestureDetector(
                  onTap: () => a.inc(),
                  child: Text(a.count.toString()),
                ),
                SizedBox(height:100.0),
                GestureDetector(
                  onTap: () => b.inc(),
                  child: Text(b.count.toString()),
                ),
              ],
            ),
          );
        },
      ),
    ),
  ),
)

It seems to be working just fine. A non-nested approach works as well:

ScopedModel<ModelA>(
  model: ModelA(),
  child: ScopedModel<ModelB>(
    model: ModelB(),
    child: Column(
      children: [
        ScopedModelDescendant<ModelA>(
          builder: (_, __, model) => GestureDetector(
                onTap: () => model.inc(),
                child: Text(model.count.toString()),
              ),
        ),
        SizedBox(height: 100.0),
        ScopedModelDescendant<ModelB>(
          builder: (_, __, model) => GestureDetector(
                onTap: () => model.inc(),
                child: Text(model.count.toString()),
              ),
        ),
      ],
    ),
  ),
)
like image 183
RedBrogdon Avatar answered Sep 28 '22 10:09

RedBrogdon