MeteorFlux Flow

Except I’m using React. :smile:

I like the idea of avoiding a dispatcher’s event system and just using AppState as the single source of truth. But one nice thing about a dispatcher is that you can throw a logger in before responding to an action so that every action in the app is recorded. Is there something similar for AppState? It’d be great if we could do something like

AppState.beforeSetOrGet(function(setOrGet, key, value){
  logger.log('AppState action', setOrGet, key, value);
});
1 Like

AppState is not supposed to substitute the Dispatcher. It’s supposed to change how Stores (or whatever you call your app logic) communicates with Views (Templates).

Yes, I forgot to write it in the docs but it’s something we need. I already have a package for doing hooks.


BTW, I have released a new version of AppState (1.1) with a new api: AppState.modify(). You can use it instead of AppState.set() if you want to follow a Redux architecture.

Whenever you want to change the state of your app, you can use this syntax:

AppState.modify('string', function(action, state = false) {
  switch (action.type) {
    case 'SOMETHING_HAPPENED':
      state = 'I am a string';
      return state;
    case 'OTHER_THING_HAPPENED':
      state = false;
      return state;
    default:
      return state;
  }
});

The state string will change when those actions are dispatched:

Dispatcher.dispatch('SOMETHING_HAPPENED');

AppState.get('string') and {{string}} will be invalidated with the new 'I am string' value.

1 Like

So AppState.modify is like a reducer in Redux. This replaces this functionality?

Dispatcher.register(function (action) {
  // ...
});

So we can choose between using Dispatcher.register combined with AppState.set, or just use AppState.modify as a reducer… am I close?

You can use two approaches right now:

Flux (action centred logic):

// default states:
AppState.set('string', false);
AppState.set('number', 0);

Dispatcher.register(function(action){
  switch (action.type) {
    case 'SOMETHING_HAPPENED':
      AppState.set('string', 'I am a string');
      AppState.set('number', 123);
      break;
    case 'OTHER_THING_HAPPENED':
      AppState.set('string', false);
      AppState.set('number', 456);
      break;
});

Redux (state centred logic):

AppState.modify('string', function(action, state = false) {
  switch (action.type) {
    case 'SOMETHING_HAPPENED':
      return 'I am a string';
    case 'OTHER_THING_HAPPENED':
      return false;
    default:
      return state;
  }
});

AppState.modify('number', function(action, state = 0) {
  switch (action.type) {
    case 'SOMETHING_HAPPENED':
      return 123;
    case 'OTHER_THING_HAPPENED':
      return 456;
    default:
      return state;
  }
});
1 Like

Awesome. Choices are good! :smile:

Hi @luisherranz. Great work and very interesting thread!

I was wondering are you planing to update Cart example project to use AppState/ReactiveState and Dispatcher Helper?

Thanks @darkomijic.

Well… we are iterating quite quickly over that AppState idea.

The original AppState has become ReactiveState because it looks like some people is actively using it and it may serve many purposes. This way we can freeze its API and people can start using it without expecting big changes. It’s not a singleton anymore, although you can still use it like that.

We still would like to add hooks to ReactiveState so we can move Blaze helpers to a different package for those out there using it in combination of React.

On the other side, we are working in a new AppState, which is an opinionated solution to create “Redux-like” apps in Meteor. This new AppState only allows get and modify (set is forbidden) so any change of the state must be initiated by an action. AppState is still a singleton.

When everything is stable and we have found out the best solution to manage state in a MeteorFlux app we will update our examples and create a good guide for it :smile:

Until then, feel free to experiment with AppState or ReactiveState and let me know what you think about it here or in the Github issues!

2 Likes

Thanks @luisherranz!
I am experimenting with two solutions for Flux architecture at the moment. Yours and meteor-space:flux I don’t have much time to decide which way to go. So I will soon have some feedback from my side. I can share both projects if you have time to glance at them. Both solutions include Astronomy as ODM layer. Astronomy is very young but it is much more elegant and powerful than SimpleSchema and tons of other packages that go with it for serious and large app.

I like your train of thought and simplicity of your solutions (in a very good and positive way, no unnecessary or complicated things, so your solution is very flexible).

But I really like CQRS and Event Sourcing from Space* projects.

I had no idea @CodeAdventure created a new, simplified version of his space:ui. I’ll take a look.

Well, what I am trying to figure out right now is not only the best way to create a Meteor & Flux application, it has to be extensible as well. That means, third party developers can jump in, create a new package to add functionality to the app but they can’t change the core. The same for designers and themes. AppState is working great in that situation.

For a normal app, where the team of developers can modify any part, things are much easier and most of the Flux implementations should just work fine.

Doesn’t CQRS break the uni-directional flow of Flux?

AppState.modify('string', function(action, state = false) {
  switch (action.type) {
   case 'SOMETHING_HAPPENED':
        return 'I am a string';
   case 'OTHER_THING_HAPPENED':
        return false;
   default:
        return state;
  }
});

So in this redux style case, you can avoid Register() and just use AppState.modify(), and if you return the same state without changing anything a === comparison on that AppState value will show that it’s the same variable as before (as in for shouldComponentUpdate)?

Yes, that’s the idea behind that syntax.