MaikuB / blog-comments

Tracks blog comments made at https://dexterx.dev
0 stars 0 forks source link

Managing UI state in Flutter with MobX and provider - Dissecting a Hacker News app #3

Open utterances-bot opened 4 years ago

utterances-bot commented 4 years ago

Managing UI state in Flutter with MobX and provider - Dissecting a Hacker News app

https://dexterx.dev/managing-ui-state-in-flutter-with-mobx-and-provider/

raviyadav5951 commented 4 years ago

"The MobX for Dart documentation also suggests using provider" can you please give the reference where they actually said this in documentation.

MaikuB commented 4 years ago

https://mobx.pub/guides/stores#using-providers-to-avoid-singletons

This is the same page I mentioned on that talks about the widget-store-service triad

raviyadav5951 commented 4 years ago

https://mobx.pub/guides/stores#using-providers-to-avoid-singletons

This is the same page I mentioned on that talks about the widget-store-service triad

Thanks

MaikuB commented 4 years ago

No worries. I've updated the post with that link too since some may not have opened it from the previous paragraphs

tonyaxo commented 4 years ago

Hi, I have question about tests, for example my store looks like:

abstract class _CategoryStoreBase with Store {

  final ApiService _api;
  final AsyncMemoizer _asyncMemorizer = AsyncMemoizer();

  _CategoryStoreBase(this._api);

  @observable
  model.Category active;

  @observable
  ObservableFuture fetchCategoriesFuture;

  @observable
  ObservableList<model.Category> list = ObservableList<model.Category>();

  @action
  Future<void> fetch() async {
    fetchCategoriesFuture = ObservableFuture(_asyncMemorizer.runOnce(() async {
      await _api.fetchCategories().then((categories)  {
        print(categories); // <-- IMPORTANT
        list.clear();
        list.addAll(categories);
      });
    }));
  }
}

Just like in yours example than I'm trying to write test for this code:

  test('Fetch store list', () async {
    .....
    final store = CategoryStore(api);
    await store.fetch();
    print(store.list);                                  // []
    expect(store.list.isNotEmpty, true); // here it's false (list is empty)

  });

but after test crashed it's prints not empty list (see IMPORTANT line) seems like it doesn't wait for fetch(). Whats wrong?

tonyaxo commented 4 years ago

After that I rewrote my code:

@action
  Future<dynamic> fetch() async {
    return _asyncMemorizer.runOnce(() async {
      var categories = await _api.fetchCategories();
      list.addAll(categories);
      return categories;
    });
  }

and test:

    final store = CategoryStore(api);
    var categories = await store.fetch();

    expect(categories.isNotEmpty, true);
    expect(store.list.isNotEmpty, true);

now It works, but how to get work previous example? and why we should use fetchCategoriesFuture?

MaikuB commented 4 years ago

Hmm I double checked my examples and don't see where I've used the then callback that's similar to how you work with JavaScript's promises. I believe your first one fails because you don't actually await for the fetching to be done within the fetch method.

In your first example you have

@action
  Future<void> fetch() async {
    fetchCategoriesFuture = ObservableFuture(_asyncMemorizer.runOnce(() async {
      await _api.fetchCategories().then((categories)  {
        print(categories); // <-- IMPORTANT
        list.clear();
        list.addAll(categories);
      });
    }));
  }

fetch here is expected to return a Future (i.e. do some asynchronous computation) but it only does a synchronous operation of setting the value of fetchCategoriesFuture. What should fix it is if you return fetchCategoriesFuture within the code for fetch.

Regarding why you would use fetchCategoriesFuture, I assume you mean why you would use an ObservableFuture (which is the object type). This is so you can use MobX's Observer widget (or other reactions) to respond to status changes. This is similar to how you would pass a Future to a FutureBuilder. Using an ObservableFuture may not be necessary but allows you to be consistent in using MobX's APIs to respond to state changes

tonyaxo commented 4 years ago

Thanks for your answer. So, with MobX I should use ObservableFuture instead of FutureBuilder or it's possible to combine them?

MaikuB commented 4 years ago

No at I said it may not be necessary. It's up to you