Redux approach on Meteor?

Well,

After some tries and plays with ReactiveVar and ReactiveDict and trying to have a global state between client and server without Session or Collections, I came up with some approach heavily inspired by Redux.

What do you guy thin about it?

Thanks.

3 Likes

That’s very cool :thumbsup: I don’t understand why the reducer is in a Meteor method though. Is that for when you need to persist something to Mongo? (in the counter example it’s just local state)

Yes, I thought that makes sense a reducer be a Meteor.method, so it can interact over the persistence layer.
I made a update just now to reduce de Meteor.call boilerplate and make de API looks even more like Redux.

1 Like

I cant try it atm, but on 1st look it seems like that INIT dispatch is called every reload reseting ReactiveDict store ?

No, INIT is called only at first page load, client refreshes doesn’t call it again and state is maintained :slight_smile:

@SkinnyGeek1010, one of the things that I’ve noticed is how the reducer always needs to return a copy of the entire state (not a mutated one, according to the docs). What if your state object is humongously complex, and you’re just modifying one teeny tiny part of the state, wouldn’t it be a bit inefficient to have to re-copy the state just to reflect that tiny state modification you’ve made?

Is there a way to break up the state without having to create another store?

And is there a more efficient way to update the app state, especially huge ones?

@leocavalcante so I have tried implementing this and I am getting stuck on whether I should use this pattern for logging in or signup. I don’t know what the initial state would be and how that would work. Do you have a better example besides a simple counter?

@brandonmikeska, check out this blog example of how they handled using Redux for user authentication. Not sure if that helps.

Yep, that’s what having multiple reducers do. You’re only really concerned about having a slice of the single state object.

I’m on mobile so I can’t really paste in a snippet yet but the main app state would be one object with keys like ‘onboarding’, ‘viewer’, etc… Each reducer only takes care of that slice of state.

I don’t know if the root object is copied over on every action… I think it’s just every reducer returning that copies.

Yes, what @SkinnyGeek1010 said, or are you talking about multiple stores? That’s more like flux and sort of what redux is based on, which is a sort-of implementation of flux. lol

The core idea of redux is 1 store for everything and sometimes even duplicating items, see:

i have no clear answer. Up until now I just use things as is, hack with it, and because it’s not a large production app with really a lot of data (all the time) I don’t have perf issues.

I think the solution I was looking for to efficiently update the state lies in the reselect plugin.

Anyway, I think that after looking at all this, I couldn’t help but think of why I would go through all this trouble of using Redux when I could use Meteor’s reactive libraries to do this?

I feel like in order to make the best use of Redux, I have to pile on a bunch of other Redux stuff on top of it, normalizr, reselect, redux-react-router (if I want to make it work with React Router).

Wouldn’t it have been easier to use ReactiveDict or ReactiveMap as the store (except Mongo.Collection data) and let Tracker do the dispatching?

Edit: In addition, how has Redux reconciled with the upcoming .observe() API of React that loads into this.data? It doesn’t seem like they’ve baked that in just yet.

Hi guys, my final thoughts about Redux/Flux on Meteor after these studies was just… don’t use it! LOL.
I think Meteor already has its own way of architecture things using pub/sub and collections. I haven’t found a satisfiable solution of using Redux on Meteor yet, I’ll keep looking @SkinnyGeek1010 projects and meanwhile using what Meteor offers out-of-the-box.

1 Like

I agree with @leocavalcante, using Flux within Meteor is kinda missing the point of why Flux was created. We already have the unidirectional flow with the subscriptions on Meteor. It is pointless to use Redux unless you REALLY want the time travel and action log. As much as I love Redux, it is a pretty high price to pay in complexity.

5 Likes

I played around with the Redux dev tools and honestly, it was nice getting it to work, but only played with it for like 2 minutes before I got bored with it :expressionless:. It is not that great. I have more fun using Mongol/Constellation.

There is one thing I took away from Redux and it’s the way they connect the data to the component. So I took that connect concept and made it so that you can connect Meteor data to a component and it seems to work quite well:

@ReactiveComponent(function () {
  return {
    loading: !Meteor.subscribe('todos').ready(),
    todos: Todos.find().fetch()
  }
})
export default class TodoList extends Component {
  
  renderTodos() {
    const { todos } = this.props;
    if (isEmpty(todos)) {
      return false;
    }
    return (
      <ul className="list-group">
        {todos.map((todo) => {
          return (
            <TodoItem key={todo._id} className="list-group-item" todo={todo} />  
          );
        })}
      </ul>        
    );
  }
  
  render() {
    const { loading } = this.props;
    if (loading) {
      return (
        <div className="alert alert-warning">Loading</div>  
      );
    }
    return (
      <div>
        <h1>Todos</h1>  
        {this.renderTodos()}
      </div>
    );
  }
}

Essentially, ReactiveComponent is a function that takes a function as first parameter that returns Meteor reactive data, and the second argument is a React component you want to wrap. It returns a new component that is able to access the Meteor data using this.props instead of this.data.

Wat? lol. Time travel and seeing the state tree change over time is super nice. You can also make commits and reset instead of reloading the entire app when debugging (using it while debugging is much more useful).

If anyone wants to try it out (devtools) here’s a repo (redux branch)

I didn’t get a chance to play with the time-traveling, commit and reset features. I think I was annoyed that the action log was sorted in ascending order because it made me have to scroll down when a new action was logged, so I think I moved on lol.

Just updated to 1.2, switched to ECMA2015 and added a React example sharing the same state within Blaze.

1 Like