MeteorFlux Flow

I have included FlowRouter in the shopping cart example.

What I have done is very simple yet, but it looks promising.

I have added a new “kind of store” called CatalogRouter. It’s not called Store because I thought it was too long (CatalogRouterStore) but in a sense, is just another Store which takes care of the Catalog routing.

FlowRouter helps converting url requests to actions:

FlowRouter.route('/products/:page', {
  action: function(params) {
    Dispatcher.dispatch({ actionType: "GO_TO_PRODUCTS_PAGE", page: params.page});
  }
});

After that, the Store takes control. It has useful get methods for the Views, like getActualPage(), getNumberOfPages() or getNextPageUrl(). The views consume them to render the correct pagination, urls, etc.

In my last reply I was talking about using Tracker.autorun to keep coherence. This Store is in charge of that as well. For example, it checks reactively if the user is in a page which doesn’t exist anymore and solves the problem.

And… that’s it.

This is the new Router-Store file:

http://cartflux.meteor.com/

Next step: start messing with the layout and see how Flux, FlowRouter and FlowLayout fit together there.

PS: I have also uploaded it to scalingo because I want to test it. So far so good. Super easy to deploy:
https://cartflux.scalingo.io/

2 Likes

That is some awesome content :blush: keep posting!

1 Like

Some news here.

At this point, I wanted to include dependency injection in the stores (so they are easier to test). At the same time, I run into problems with loading order, globals and circular dependencies.

I have fallen in love with Meteor’s reactivity lately, so I thought, why not to apply it to this problem: I created a package called Reactive Dependency:


I did a very simple example with some stores depending on each other:

It can be used without Flux as well.

Back to the Shopping cart example, these are the things I have done since the last update:

  • I have included the Reactive Dependency package and it’s working great. No more loading order or globals problems.
  • I have done some refactoring of the code after reading the Meteor Style Guide.
    Now I am using var self = this; everywhere and new to create my Stores.
  • I have added a MainRouter which is in charge of retrieving routes.
  • I have added a MainLayout which is in charge of changing the layout. I am using FlowLayout now. Working great.
  • I have created client, both and server folders and move things where they belong.
  • client: views, stores, layouts, routers.
  • both: methods and collections.
  • server: publications.
  • I have added what I call a “Look ahead” publication.

What I mean for a “Look ahead” publication is that it is subscribing to both the previous and next page, instead of only the current page. That means when you go to the next page, the data is already there so it feels realtime.

I am still trying to figure out some things:

  • Who should do subscriptions. Templates? Stores? Routers?
  • Are routes “App State”, “User input” or a mix between both?

If routes are App State, they should be retrievable from Stores. But if they are “User Input” they should dispatch actions.

I have been thinking about the “Everything is a package” pattern as well. And I think it’s great. Meteor itself, Telescope or Atom look are like that. When things start to get complex, it’s better to create a package. So, for example, the “Look ahead” publication probably deserves its own package. But then you can use Flux to organise all the pieces together: keep the App State of your app and populate your Views.


http://cartflux.meteor.com/
https://cartflux.scalingo.io/

I just find this thread and I’m very impressed. I’d love to see how this can be tested with velocity. Would you mind to add tests on your cart repository ?

1 Like

Yes, I wanted to add dependency injection first. So it’s my next step : )

But I am still trying to figure out the best way to deal with routes and layouts as well.

1 Like

I have done another example of you how to pass data between templates for another thread.
It’s very simple but here it is:


http://meteorpad.com/pad/36dwXz9ktQK3SJGgB

And this is the thread:

Maybe I don’t understand your use-case entirely, but we use state-machines for this kind of thing (ecommerce, order state, complex workflows that touch multiple APIs). We find state machines really help manage the complexity.

Here is a Meteor wrapper for a state machine we are using:

1 Like

Thanks for the contribution, @maxhodges

As I see it, a finite state machine is a very useful tool, but it’s not the same use-case here. Flux is a software architecture which replaces MVC.

I coded a very complex state machine and I used it extensively with PureMVC. It was based on chained notifications. It worked well but it was hard to debug. Flux doesn’t allow chained notifications for that reason.

In order to work within Flux I think the workflow would be like this:

1.- UI still dispatches actions, for example: “USER_CLICKED_PLAY_BUTTON”.
2.- Stores register for those actions, and can change the State Machine state. For example: PlayerStateMachine.play().

Now the obvious next step would be:

3.- The State Machine changes its state and dispatch an action with the new state, so Stores can act. For example: “MEDIA_PLAYER_STARTED_PLAYING”.

Problem with that: you got a chained notification, because “USER_CLICKED_PLAY_BUTTON” hasn’t finished yet. No good.

The only solution which comes to my head right now is to make the current state of the State Machine part of the “App State”. In other words, make the state reactive:

3.- The State Machine changes its state, which is reactive. Anything depending on that state recomputes thanks to Tracker.

Image PlayerStateMachine.getState() retrieves a reactive variable with the state. Then UI can update like this:

Template.PlayerView.helpers({
  playClass: function () {
    if (PlayerStateMachine.getState() === "play")
      return "playing";
    else
      return "not-playing";
  }
});

And Stores can update like this:

// Inside PlayerStore
Tracker.autorun(function(){
  var state = PlayerStateMachine.getState();
  if (state === "play")
    mediaPlayer.play();
  else if (state === "pause")
    mediaPlayer.pause();
  else
    mediaPlayer.stop();
});

Any thoughts?

1 Like

I have added some tests to the Catalog Store of the Shopping example:
https://github.com/meteorflux/cartflux/blob/master/tests/jasmine/client/unit/CatalogStoreSpec

I’m using Jasmine which has unit testing in the client. I’m not sure if you can use Mocha as well.

I’m testing only the Stores because most of the logic should be there. Tests look like this:

it('should add a product to the Catalog Collection', function(){
      Dispatcher.dispatch({
        actionType: "ADD_PRODUCT",
        product: { name: "Test", price: 12345 }
      });
      expect(Meteor.call).toHaveBeenCalledWith(
        "CatalogStore.addProduct",
        { name: "Test", price: 12345 }
      );
    });

it('should not return any prodcuts in this search', function(){
      Dispatcher.dispatch({
        actionType: "USER_HAS_SEARCHED_PRODUCTS",
        search: "Test nonexistent product"
      });
      expect(catalogStore.getSearchedProducts().fetch())
        .toEqual([]);
    });

This is very similar to what Facebook is doing with Jasmine and Jest:
http://facebook.github.io/react/blog/2014/09/24/testing-flux-applications
(I don’t see the need for Jest in Meteor, by the way)

Facebook recommends to move as much logic as you can to the stores, so it can be tested easily. Remember: Your Views should only dispatch actions and retrieve data from Stores.

Maybe integration tests are not needed because views are very simple and you are covered with unit tests for Stores and some kind of End-to-end tests for the whole application. Anyway, I’m not an expert on testing so any suggestions are welcomed!


Besides, I have done some refactoring of the Router, Layout and Store structure.

This is how a Store looks like now:
https://github.com/meteorflux/cartflux/blob/master/client/stores/CatalogStore
As you can see, the only public methods now are the getters.

This is the Router:
https://github.com/meteorflux/cartflux/blob/master/client/routers/MainRouter
Which is used to dispatch actions and retrieve routes.

And the Layout:
https://github.com/meteorflux/cartflux/blob/master/client/ui/layouts/MainLayout
Which only renders the correct layout when it receives an action.

Of course, you can use your favourite structure in your own Flux app. Only the dispatcher is needed.

2 Likes

I’ve just added some tests for the Cart Store as well:
https://github.com/meteorflux/cartflux/blob/master/tests/jasmine/client/unit/CartStoreSpec

Some examples of tests:

it('should remove a cart item if decreasing and quantity is 1', function(){
      spyOn(Cart, "findOne").and.returnValue({ quantity: 1 });
      Dispatcher.dispatch({
        actionType: "DECREASE_CART_ITEM",
        item: { _id: 123 }
      });
      expect(Meteor.call).toHaveBeenCalledWith(
        'CartStore.removeCartItem',
        123
      );
    });

it('should retrieve the userId as the cartId when the user is logged in', function(){
      spyOn(Meteor, 'userId').and.returnValue(123);
      Dispatcher.dispatch({ actionType: "LOGIN_SUCCEED" });
      expect(cartStore.getCartId()).toBe(123);
    });

Very straightforward.

The only issue was with ReactiveDict. If you want it to survive to Hot Code Pushes, you have to give it a name. If you try to create a second instance of your object, it throws a Duplicate Name error. I don’t know yet how to solve that.

1 Like

@luisherranz it seems you really like to re-invent the wheel :wink: every step you take is basically what the space framework boils down to at the end of the day. You would even get a more convenient class system in Javascript for free with dead-simply dependency injection that is not tied to Meteor.autorun (which makes it even easier to test).

1 Like

The approach is still different. I’m only using a simple flux dispatcher. The rest is pure Meteor, but organised “the flux way”. No classes for stores, mediators, commands, constants…

Actually, what I’ve been thinking the last week is that I need to accept the way Meteor works, and if Meteor is based on the use of globals, I can’t go against that, because then you can run into problems and overcomplicate things.

My reactive dependency injection package does four things:

  • Solves circular dependencies.
  • Gets rid of loading order problems.
  • Gets rid of globals.
  • Add dependency injection.

But Meteor is designed to be used with globals and to solve loading problems using packages and Meteor.startup().

In most cases, globals, loading order and circular dependencies can be solved by using namespaces, like:

MyApp = {};
MyApp.SomeStore = {......};

With my Dependency package you can use dependency injection in your test initialisations like this:

beforeEach(function(){
  // Internal Dependencies
  var countersStore = new CountersStore();
  var catalogRouter = new CatalogRouter();
 
  Dependency.add('CatalogRouter', catalogRouter);
  Dependency.add('CountersStore', countersStore );

  // Store we want to test
  var catalogStore = new CatalogStore();
});

But if you use globals instead, you can do:

beforeEach(function(){
  // Internal Dependencies
  CountersStore = new CountersStore();
  CatalogRouter = new CatalogRouter();

  // Store we want to test
  CatalogStore = new CatalogStore();
});

which is simpler and it just works.

So I don’t think my Dependency package is worth anymore and I will try to get rid of it in my code to keep things as simple as possible (and as meteorish as possible).

I’ve been thinking about the “Everything is a package” pattern as well.
I watched the video of the Telescope refactoring. It’s very interesting:

Sacha namespaced everthing under the a Telescope global and everything is now in packages.

I have used the “Everything is a package” pattern in the past, for an application where third party people were able to add functionalities.

The problem I found with this pattern is that packages have to talk with each other, and strong dependencies appear. In consequence, packages are weaker and less reusable. And a new question arises: “How should packages communicate with each other?”.

Flux is a great way to communicate different parts of a modern app, so I see great potential combining “Everything is a package” and Flux. I suggest:

  • Namespace your app, like Telescope does.
  • Put as much logic in packages as you can.
  • Make packages as agnostic as you can: avoid dependencies between packages.
  • Use stores mostly to interconnect those agnostic packages between each other and the UI.
  • Avoid using stores for complex logic: abstract it and create reusable packages.

There are a lot of packages out there which depend on Iron Router for example. That’s not good. What if I want to use Flow Router, or not to use a router at all?
The only exception is where your package is extending the functionality of other package, like accounts-ui extending accounts-base.

If you want your app to be extensible by third party people you still need to add stuff like hooks (filters) and modules like Telescope does (I yet have to figure out how can a flux dispatcher and hooks for extensibility work together).

Everything above is only my opinion. Feel free to comment or criticise : )

3 Likes

Hey @luisherranz,
I am already using the “everything is a package” pattern and it works great. Also the Space.Injector solves all of your mentioned problems without being Meteor-aware (which is also something a lot of people forget, its just Javascript, not Meteor)! And I am not really sure why runtime dependencies should be reactive, this makes the code even more complicated and coupled.

Here is your example how I would write and test it with space:base:

// Simple sugar for javascript inheritance (not required)
CatalogStore = Space.Object.extend({
  // just a prototype property, no magic
  Dependencies: {
   countersStore: 'CountersStore',
   catalogRouter: 'CatalogRouter'
  }
});

beforeEach(function(){
  // Store we want to test
  var catalogStore = new CatalogStore({
    countersStore: new CountersStore(),
    catalogRouter: new CatalogRouter()
  });
});

in your real app you want the injector to wire things up:

var injector = new Space.Injector();
var countersStore = new CountersStore();
var catalogRouter = new CatalogRouter();
injector.map('CountersStore').to(countersStore);
injector.map('CatalogRouter').to(catalogRouter);

var catalogStore = new CatalogStore();
injector.injectInto(catalogStore); // provide runtime dependencies

this was the bare-metals approach, only using the injector and doing everything else by hand.
Of course space comes with convenience like namespace lookups:

var injector = new Space.Injector();
injector.map('CountersStore').asSingleton();
injector.map('CatalogRouter').asSingleton();
injector.map('CatalogStore').asSingleton(); // deps are auto-injected

One thing you don’t consider is this: there is no way to decouple everything. If any parts of your app talk with each other (in any way) then they are coupled (in some way). Maybe not to implementation details (the Meteor way) but even with your dispatcher and/or dependency injection the various parts are coupled at runtime -> its the messaging contract that couples them.

Think about it: you can build the most generic, decoupled package possible, but still something, somewhere has to send to or retrieve messages from it. These messages are coupling, even when they are abstracted behind string constants and extremely loosely contracts like with flux dispatcher. In my opinion that’s even worse, because now you have coupled things together but have no explicit contract defined how messages have to look like.

Coupling means this: “Do I have to change anything else if I change this part of the code?”. So if you change how your package receives parameters (or which) then you have to update all callers too, even if they never have a direct reference to the receiver.

The other aspects like namespacing, globals etc. are not really relevant and a matter of taste. There are people that like the “java namespacing pattern” and others who hate it. You can build your structure any way you want and even the Meteor way (simple globals) has its place.

With dependency injection you can remove the static coupling (which is great for testing) but you can never remove runtime coupling, because that’s what your app is made of. (Actually you can, there is a pattern called “anti-corruption layer” which means that you use mediators between parts of your app that translate the api messages of both parties, but that’s another story).

In my experience it works like this: You start mostly with very app-specific code, small encapsulated classes that do one thing well and some “controller”-like parts that wire them up. Eventually there appear some bigger-scope concerns where you think “hmm … this could become its own package” – but still it doesn’t have to be “generic” or “agnostic”. The code inside the package can be extremely self-coupled and straight-forward. Then eventually you come across functionality that is really re-usable, like e.g. a package that wraps the Stripe api which you could use in more than one application.

The “generic” package, shared between multiple apps sounds great BUT it comes with a big price tag: maintenance of the API contract. In my opinion you have to carefully consider where it pays off and which parts of the code should not become too generic.

To sum it up: the only benefit you get from using a messaging dispatcher / event bus / any kind of middleware layer, is that you can hook into the message flow. That’s it, there is nothing more. Forget about these patterns in other languages (where they are used to decouple), we are in Javascript land where its even possible to switch your pants while you are shitting them. Think: I could replace Meteor with something else, before calling a method that uses it – this would be a (hacky) way of dependency injection.

But what I really like about messaging patterns is the possibility to make the contract between packages explicit. Because that’s one downside of dynamic languages: you can’t rely on the compiler to tell you if you called something “the right way” which is a pain while refactoring.

Here is a simple self-checking message that you can send to my stripe package:

class Stripe.ChargeCustomer extends Space.Struct

  @fields:
   customerId: String
   total: Number
   description: String
   ipAddress: String

this uses Meteor check internally when you instantiate the struct with a param object. Of course I use these messages also in my unit-tests etc. so that if you change the api, everything breaks and tells you that where you have to update your code to complete the refactoring.

Ok this is getting really long and confusing :smile: I hope its still understandable.

4 Likes

It’s perfectly understandable, and very interesting :smile:

I agree with most of things you say, actually.

It was reactive to solve circular dependencies. I agree with you that is complicated and you should avoid them in the first place.

That’s very similar to what I was doing with the Dependency package, sure.
I don’t think it’s needed anyway so I will try to get rid of it.

When I was talking about mixing “Everything is a package” and Flux together, I wasn’t talking about including dependencies to the flux dispatcher in every package. You shouldn’t do that. Packages should have an API and that’s it. No dependencies, no communications.

The dispatcher is a concern of the Views and Stores only. Those are the things which are coupled and talk to each other so your packages can be decoupled and not know about the existence of other parts of the app.

If you want to put your stores/views inside the Meteor package system, it’s ok. But I wasn’t considering them as packages/libraries.

Sure, some packages are going to be things nobody else needs. That’s not bad, but I have run into problems having to refactor whole packages just because I was just coding fast and I wasn’t “forcing myself” to make them as agnostic as I could. Then you change some part of your app and everything breaks.

I think if you force yourself to think that way, the quality of your code improves greatly. Even if your package is not useful elsewhere.

Totally agree.

Totally agree and I think that is very very useful.

For me Flux is that, a very simple dispatcher which forces you to create very simple, one-way, chains of events (dispatcher->store->app-state->view).

1 Like

I’ve been taking a look at the Flux implementation which Optimizely is using in production: Nuclear-js

They have done some very interesting stuff:

  • They use modules to encapsulate domains. They contain stores and expose actions and getters.
  • They store all the app state in a single Immutable map.
  • They do automatic data observation / rendering, very similar to Meteor’s reactivity.
  • Thanks to their reactivity, they don’t need the waitFor functionality.

This is great because it confirms that you don’t need waitFor in Meteor. I like the modules concept as well.

In the end, this made me think about different flux implementations. I’ve been thinking about space-ui as well. Our conversation looks like “who is wrong and who is right” and it shouldn’t. There are dozens of flux implementations out there and none of them is wrong or right. Space-ui is one of them and if you feel comfortable with it, go ahead. I’m sure @CodeAdventure put a lot of effort in it.

I really like the fact that Facebook only shared a bare dispatcher and let everyone else to roll out their implementations. Actually, Flux is an architecture and not a framework. The only important things are the Flux Principles.

With this thread I wanted to find out if Flux and Meteor can work together. Now I am sure they can, and I think it is actually an excellent idea.

It’s so simple to use Flux and Meteor and there are so many good implementations of Flux that I think is up to people deciding which implementation to choose. They can use my port of the Facebook’s Dispatcher and do the rest of the stuff his way, or maybe use something like space-ui where you have to learn its API and follow it.

I think it’s time for me to close this thread and write a Readme.md for the package.
I hope it’s useful for people interested in using Flux with Meteor but only want the basics.

2 Likes

@luisherranz sorry if it came across as space:ui vs. your flux implementation, that’s definitely not what I intended because I also replace space:ui with other packages if they work in a better way (e.g blaze-components is quite useful sometimes compared to my mediator pattern).

I wanted to get across that the “flux dispatcher” is just another event bus, a very common pattern which probably existed for 30+ years in software dev. The restriction that you can only dispatch one message per loop might be nice for Facebook but I never needed it, nor did it help me in any way. If you use Meteor’s reactivity + single source of truth patterns than there is not much need for client-side messaging anyway because everything is data-driven.

One of the example by Facebook was the unread messages counter for the in-page messenger. They had some bugs with weird states etc. but honestly you will never have those problems with a “normal” Meteor application because reactivity syncs all parts automatically for you. There is only one source of truth: the database.

The only really exciting thing about React / Flux is the possibility to do server-side rendering and the idea of “re-render everything” which greatly simplifies your thinking about UI. That’s what most people get excited about but only the second part can be applied to Meteor easily.

I actually move more and more away from using flux stores and messaging in the front-end because its just not needed (in most cases).

Anyway, thanks for putting all this research effort here, its definitely a great resource for people thinking about these architectures and also was a great mirror for myself (that’s why I couldn’t shut up :-D)

No it wans’t, no problem : )

In my opinion, Flux is more than just a message bus. It’s a set of useful, keep-it-simple, principles. Maybe not for all cases but, what is?

I agree, Meteor’s reactivity is incredible and there is no need to stop using it.
Look here: https://github.com/facebook/flux/issues/209

No problem, your comments and expertise are welcomed of course.
I know you went thru all this but I wanted to do it as well.

By the way, in this interview, Matt DeBergalis said two interesting things:

  • Old web is page-based but we can do better. Meteor is here to help us create apps, not webs.
    IMHO, IronRouter centric apps are page-based again, that’s the reason I wanted to check something new.
  • So far, Meteor has been architecture agnostic but in the future that is going to change.

He actually said way more than two interesting things of course : )


Now I am about to start a big project where I have to design an extensible Meteor app, similar to what Sacha is doing with the Telescope refactoring. I will see how Flux can fit in a project like that (if at all) but I think I have an idea.

I hope I can get some time out soon to do a proper readme for the meteorflux:dispatcher package but I had a lot of work lately. I’ll do soon!

1 Like

I have updated the README file of the package. I am sorry it took so long but I’ve been very busy.


https://atmospherejs.com/meteorflux/dispatcher

I hope it is clear enough to reflect what I have learned here, but if you feel like something is missing let me know and I will update it.

I am already studying other things, because the app I need to build now is more complex. I am testing Flux but with global state objects and global getters (like NuclearJS or Facebook and Baobab do) mixing it with an extensible pattern (like WordPress or Telescope) and a template system (like Ghost) all organised with modules using the everything-is-a-package pattern.

Anyway, this MeteorFlux Dispatcher will remain as simple as it is, so anybody wanting to build something with Meteor and Flux can try it out.

I may come back if I consider I have learned or worked with something which may benefit this thread. It looks like a lot of people was paying attention : )

And of course if you are playing with Meteor and Flux and have any doubt feel free to reply here and we will work it out together.

Cheers!

3 Likes

yes, your package supported methods that easy to change params and query params. And flow-router really suite for FLUX .

My stacks:

  • meteorhacks:flow-router
  • izzilab:iz-flux (just ported from facebook Dispatcher)
  • reactjs:react
  • izzilab:react-layout (my package to define layouts and render content for reactjs)

@luisherranz Thanks for this post, it’s been great going through the thought process behind your implementation of Flux into Meteor. For the most parts I agree with you and I think the Flux architecture fits great into Meteor. I have a couple of thoughts regarding the dispatcher and the Stores.

The thought about the dispatcher is minimal, but since Dispatcher.dispatch() always takes in an actionType I think it would be more “meteor like” if it was called in the same way that Meteor.methods get called; eg. Dispatcher.dispach("SOMETHING_HAPPENED", "some data") or Dispatcher.dispach("SOMETHING_HAPPENED", {firstName: “First”, lastName: “Last” }) . This would move slightly away from Facebook’s implementation, but it makes the dispatcher look more like Meteor code.

Regarding the Stores, I don’t think they should be separated into Stores and App State. I think the stores should maintain the app state, both the variables (reactiveVar/Dict or Sessions) and the Collections. I see the stores publishing helpers directly to Blaze, essentially taking over most of what Template helpers normally do. The views/templates would directly query the Stores for the state via Store helpers. This would keep us from having helpers like:

Template.myTemplate.helpers({
  myHelper: function() {
    return MyStore.getMyValue()
  }
});

Instead we would call {{ MyStore.getMyValue }} directly from the template, making the code more clean and reusable.

For this I think it would be best to have a Store prototype that takes care of registering its helpers to Template and registering with the Dispatcher. I’ve created a package for doing that and the api is relatively simple:

PostStore = new Store('PostStore', function(){
  // String ('PostStore') is the name of the Store,
  // this is what the Blaze global helper will be called.
  // Function that initiates variables and whatever
  // else you might want to do. Basically this is .onCreated()
  // (and it might as .onCreated() to act more like meteor)
  
  var self = this;
  
  self._visiblePosts = new reactiveVar(5);

});

PostStore.helpers({
  getPosts: function() {
    return Posts.find();
  },
  getVisibleNumber: function() {
    return this._visiblePosts.get();
  }
});

PostStore.actions({
  userLoadsMorePosts: function() {
    var self = this;
    var number = self._visiblePosts.get
    self._visiblePosts.set(number+5);
  }
});

The Store package takes care of registering with the Dispatcher so the dispatcher gets called like normal, and it also registers the helpers with Blaze so the template can be

<template name="posts">
  {{#each PostStore.getPosts}}
  <h2>{{title}}</h2>
  <p>{{text}}</p>
  {{/each}}
</template>

I’ve created a fork of your excellent CartFlux example that uses this Store package, it’s on GitHub and live here (should look identical).

Like I said, I think the Stores should handle the app state, and the helpers that refer to the app state should be contained within the Stores (or as Collection helpers, eg. calculating cart total price). I do see some role for Template helpers, but having it mostly limited to a visual representation of the app state (like which class to show, helpers for #if blocks etc.)

I also think that the Stores should take care of their own subscription (since they’re handling the app state), but I haven’t figured out how that should be done, any thoughts on that?

I haven’t posted the Stores package yet, since there’s a couple of things I want to figure out before I do (subscriptions, yes/no/how? better way for actions call other actions in same store …). I will post it soon and I’ll update when I do.