Are there any examples for updating a store within another store? I have a MainStore and SignupStore I want to update field in MainStore. What is the correct approach? should I pass a reference of MainStore to the SignupStore? Or should I will put the SignupStore inside the MainStore?
I have a few Global Stores that are static. Then all the other stores are either stored on the Global Store, or generated per page and destroyed after leaving the page. The Global Store is as light weight as possible, but they allow more complex stores that are page dependent to be created with values coming from db.
Basically GlobalStore -> PageStore -> ComponentStore :) Also Page stores refer to EntityStores (EntityStores are the entity/business objects). PageStore suddenly becomes the ViewModel. Global Stores store what is the number of HTTP 500 errors, current page, global data filters, or what should come up if the user presses back button, stuff like that you don't generally put on a ViewModel of a specific page.
I don't generally have the stores communicate directly from each other but I pass args from one page to another.
@override
Widget build(BuildContext context) {
var arguments = ModalRoute.of(context).settings.arguments;
if (_store == null && arguments == null) {
_store = Globals.elementsListPageStore;
}
// It will be up to the receiving page to assemble a new store when it receives the args.
if (_store == null && arguments != null) {
ElementsListPageArgs args = arguments;
_store = ElementsListPageStore();
_store.parent = args.parentElement.elementId;
_store.parentType = args.parentElement.type;
}
return InkWell(
onLongPress: () {
print("onLongPress ${element.elementId} ${element.alias}");
},
onTap: () {
if (_store.selector) {
// If this is treated as an element selection window.
var result = ElementsListPageResult();
result.selectedElement = element;
result.isCancelled = false;
Navigator.pop(context, result);
} else {
// If this is treated as an element explorer window.
print("onTap ${element.elementId} ${element.alias}");
if (element.type == 9) {
var argument = ElementsListPageArgs();
argument.parentElement = element;
Navigator.pushNamed(context, Routes.getElements,
arguments: argument);
} else {
Navigator.pushNamed(context, Routes.getElement, arguments: element);
}
}
},
However, there are info that are used by all pages, so that's what the Global Store is for. You don't want too much on that store.
I am not sure if this is the best way to go, but has been stable enough to handle a sizeable app. Way better in my experience than using BLOC.
Thank you sir. Correct me if I'm wrong. By saying this "GlobalStore -> PageStore -> ComponentStore". You mean Global store contains PageStore and PageStore contain ComponentStore. When I put it in code, it will look like this:
abstract class _Global implements Store {
final AuthenticationService authenticationService = AuthenticationService();
final SignupStore signupStore = SignupStore(); // this is the page store for sign up page
@observable
ObservableFuture<User> currentUser;
@action
void fetchCurrentUser() {
currentUser = ObservableFuture(authenticationService.currentUser());
}
}
That looks right to me @campanagerald. A GlobalStore is mostly a composition point for all the stores. It allows you to build a hierarchy of related stores with some co-ordination built in. If a child store wants to talk to another child store, they can do so via the Global (root) store.
What you have is a tree with Global at the root and Signup as a child.
I see, thanks @pavanpodila . I also want to know how to destroy the SignupStore after the SignupPage but I can't find destroy()/dispose() function from the Store class so that I will just override it then call it inside the SignupStore.
There is no destroy() function ๐. Just create a dispose() function on the Store and call it in the Widget.dispose().
When you expose your model using the Provider package you could set it up to dispose the store when the widget is no longer in the tree. As detailed in the exposing a value section of Provider package readme.
https://pub.dev/packages/provider#-readme-tab-
Provider
builder: (context) => MyComplexClass(),
dispose: (context, value) => value.dispose()
child: SomeWidget(),
)
About that โ there's an on-going discussion (of 2 peoples... haha) on how provider can improve to simplify such interactions.
https://github.com/rrousselGit/provider/issues/46
Go ahead and give your opinion! ๐
For communication between data stores I recommend checking the best practices guide on MobX.js.
The suggest defining a parent store with a reference to child stores, and initializing each store in the parent constructor like this:
this.userStore = new UserStore(this);
UserStore will then save the root store in it's constructor:
this.rootStore = rootStore;
And then one would be able to reference any store like this:
this.rootStore.todoStore.todos.
I think it'll be a good idea to link to the best practices guide from the ReadMe file of this (amazing) library.
Good idea @yoavrofe. How about a PR ๐ค๐
It consume memory right? You are instantiating an object that are not yet being used. Would it be right that we will instantiate a store when the widgets starts using it?
Most helpful comment
About that โ there's an on-going discussion (of 2 peoples... haha) on how
providercan improve to simplify such interactions.https://github.com/rrousselGit/provider/issues/46
Go ahead and give your opinion! ๐