Flux Example App with React & Meteor

@benjamin79

Hmmm that’s going to be a tough one. In Reaktor <Router> doesn’t pass it’s props to the children so I think you would need to do this in the mean time for it to work? Even then i’m not sure…

This is something that will be resolved eventually but I haven’t had the time to check it out yet. edit now that I think of it… once defaultLayout is implemented it should be able to resolve this since it would have to clone it’s props into the children.

  Reaktor.init(
    <Router>
     
      <Provider store={store}>
         {() => <Route path="/" layout={Layout} content={Home} />}
      </Provider>

      <Provider store={store}>
         {() => <Route path="/about" layout={Layout} content={About} />}
      </Provider>
     
    </Router>
  );

@benjamin79 I’ve used Redux with FlowRouter now and it’s easiest to use Redux with FlowRouter instead of Reaktor right now. You can pass store down as a prop to get it to work.

Perhaps I can add a PR later or @arunoda to allow the Reaktor root to pass store down to props.


FlowRouter.route('/about', {
  action: function(params, queryParams) {

    ReactLayout.render(MainLayout, {
      content: <About store={store} />
    })

  }
}); 
  

Then you can connect it up like:

About = React.createClass({
  render() {
    return (
      <div>
        <h2>Email from Redux: {this.props.email}</h2>
      </div>
    );
  }
});

// watch these keys for changes and add as props to About
function mapStateToProps(state) {
  return { email: state.test.email };
}

About = connect(mapStateToProps)(About);
1 Like

@SkinnyGeek1010

thank you, i will give it a try the next days.

It’s been a little while since this thread last left off. Do we now have a better understanding of the state of the art for integrating Flux and React into Meteor apps?

I’m starting a new project and it would be great to use some of this stuff! I just want to make sure I’m using the best tools for the job.

1 Like

@adrianmcli With meteor you can use flux to store local state (not in db). This helps keep structure and eliminates reactive-dicts and session.

You can also store minimongo docs in flux if that helps. You would watch the collection and fire changed events when the data changes.

At this point Redux is the king of flux libraries overall and also the most simple.

hey @SkinnyGeek1010, your redux example looks great. do you have any examples of how you’d use it while following the ‘package everything’ approach? I imagine you’d still want to keep each feature in its own package, and include any reducers + models for that feature inside the package. not sure if you’d want to keep actions for that feature inside the package as well, or keep them all in one file. as you said

This may seem like unneeded boilerplate but it’s really nice to have a file with all possible ways to mutate the state of the app.

@efrancis Thanks! I tend to split up reducers and actions by domain… so that could be a group of features. Kind of hard to know when/how to split them up though,

actions/
  app.js
  posts.js
  comments.js
reducers/
  app.js
  posts.js
  comments.js
store.js

// then require them
import {createPost} from 'actions/posts';

I haven’t tried the package everything approach. Personally I would leave Meteor before doing that… feels like trying to tap dance with galoshes :laughing: I’m now using Webpack to use ES6 modules but it’s kind of a hack to get it working (it basically creates a server/client bundle and drops them in the meteor folder, which meteor then uses). Still is nicer than globals and large app reloads are 1.5 seconds

You should be able to just export them though since they’re just functions.

My projects are structured exactly this way. Here are a couple of open source ones (still in early stages):

https://github.com/coniel/ibguides/tree/master/packages/app-forms/lib
I’m just getting started on that one (it’s a re-write of a PHP based site I run). At the moment the only package with actions and a reducer is ‘app-form’ (WIP), so have a look at that. I used the meteor dust boilerplate to get started (it’s designed as a starting point for large package only apps). One of the main ideas of meteor-dust is that there is a global App object, to which all packages have access. I created an attribute for actions (App.actions) and reducers (App.reducers), and then when creating the store, I simply get my reducers from App.reducers (see ‘app-core/lib/store.jsx’). Since app-core is basically where the app is built, you can be certain that all the reducers will be added to your store, as it’s the last package to be run. I also setup my layout with the in app-core. (note: I use a different createStore() for the server and client because I’m using SSR and I don’t want the server side render to have all the debugger stuff in it).

My other project is here https://github.com/coniel/coniel/tree/master/packages
It’s much larger and much messier (I’m planning to refactor it next week). There are a few packages still using Flux instead of Redux (I started out with Flux but then switched).

As a side note, I’m planning on releasing a few packages on atmosphere next week. I’ll probably start with my file-upload and forms packages. They are both designed for projects using React. They won’t rely on Redux or the meteor-dust way of doing things, but I’ll build add-on packages that will create and hook up Redux actions and reducers to them, so no extra work is needed for projects using Redux. (My goal is to turn all of my code into a library of fully featured yet easily extensible packages similar to the socialize packages.)

The file upload package basically provides an invisible <FileInput> component that will turn it’s parent into a file input that is hooked up to handle everything (the package also provides authorisation handling and an API for editing/removing files).

The forms package is a very stripped down version of aldeed:auto-form for React. It only handles form validation (it doesn’t build forms for you à la ‘{{> quickForm}}’ or do inserts/updates automatically). Basically you are provided with a <Form> component to which you provide an id, schema (aldeed:simple-schema) and onSubmit callback. The <Form> component will then attach the corresponding schema value (including label, placeholder, defaultValue…) to each child input based on it’s name. When a user attempts to submit the form, it first validates it and if there are no errors calls the onSubmit callback, otherwise it will add the error message as a prop to each invalid input. It won’t come with any UI elements for inputs, those will be in a separate package (I’m using Material UI so I’ll create a package for that). That way the main package stays UI agnostic and anyone can create an extension for it (similar to theme templates in autoform).

PS: @SkinnyGeek1010 what do you dislike about an all packages approach? I find it makes it super easy to test, maintain, share and re-use code compared to the regular Meteor way. Also having a package.js file is great to understand exactly what is part of a certain module and what it exports.

They’re very verbose to setup and still leave globals. I tried spiking a project using them but IMHO it’s not much better than using a file with a global object as a namespace and private variables. It’s also not exactly easy to share code without a way to pull in packages from Github or a private repo (meteorite was great for that). The one plus is that they control load order!

In general it seems like a hack to try and get real modules instead of using the JS ecosystem standard of modules.

The real issue is that MDG has been sticking their finger in their ears and saying ‘la la la la’ for years. I understand why Meteor didn’t ship with them as 2012 was uncertain for AMD/Browserify but Browserify has been stable for over a year now and started in 2012. Supposedly ES6 modules will hit core but I doubt they will come this year. Maybe 2016 :frowning:

2 Likes

What meteor package would you use instead of the npm ones you have on your meteor-flux-leaderboard repo?

Would kyutaekang:react-redux be sufficient?

1 Like

I would avoid doing so at all costs. Flux/Redux move quickly and they’re constantly out of date on Atmosphere. Most of them use meteorhacks:npm anyway so all you’re gaining is a slightly faster install at the cost of being locked in.

Just found it cleaner to use only Meteor package, but you score a point here.

1 Like

Yea i’ve found out the hard way. You save 2 mins now and lose 2 hours later :smile:

Also the React ecosystem lives on NPM so you’ll need to pull in other great packages like classnames and others.

Am still wondering about what’s the best way to propagate the event back to the view components. Let’s see in detail how the action on the “Add 5 points” button works in your very nice meteor-flux-leaderboard example.

  1. The event is bound on the button.inc here : https://github.com/AdamBrodzinski/meteor-flux-leaderboard/blob/redux/client/components/SelectPlayer.jsx#L16
  2. The interesting stuff starts where the onClick event is handled. We have ```store.dispatch(Actions.incrementScore(this.props.selectedId));
 3. The action incrementScore is triggered with the playerId passed in parameter. It updates the DB and return the action name 'INCREMENT_SCORE'.
 4. The action name returned is sent to the store (https://github.com/AdamBrodzinski/meteor-flux-leaderboard/blob/redux/client/store.jsx)
 5. The store use the reducers to process the action. https://github.com/AdamBrodzinski/meteor-flux-leaderboard/blob/redux/client/reducers.jsx#L44 The application state is in this case not changed.

Now it's a bit more tricky and would appreciate your help to explain this behavior, the way Flux and React are handled in Meteor.js. In this step, you mention in your comments : 

```normally in redux you would update and merge state here but since have minimongo to do that for us we'll just wait for the flux-helper to fire a COLLECTION_CHANGED dispatch after the increment update. Since we're doing that we'll just return the old state to prevent the UI from re-rendering twice.```

When is the COLLECTION_CHANGED event caught? Seems this is done via the ```this.sub``` in the AppContainer https://github.com/AdamBrodzinski/meteor-flux-leaderboard/blob/redux/client/components/AppContainer.jsx#L7 - right?

How would we handle the events if not using Meteor Collections?

As far as I understand, in your code, you're sending all the properties from top to bottom, through all React components. Correct? Isn't that a bad practice, making sending data more complex than it should? Even when regrouping each major component in a container?

Or would listening to changes directly in sub-component bring any problem on the long run and go against Redux, making harder to follow the flow of information? Maybe this is more of a personnal (or organisational) choice.

I think what is not so clear to me yet is the way we connect Flux and Reac.js. This seems to be done here in the AppContainer : https://github.com/AdamBrodzinski/meteor-flux-leaderboard/blob/redux/client/components/AppContainer.jsx#L20-L33. Have red the http://rackt.org/redux/docs/basics/UsageWithReact.html docs but any input will definitely help!

I'd be very happy to hear your thoughts and remarks about this!

I’ll get back with a much more though answer later but for now i wanted to mention that you can still use the Meteor mixin for all DB data and then use Redux for data that’s not persisted (local state that needs to be shared globally in a sane way).

The tradeoffs are that you’re more coupled to Meteor and the mixin this way. The flux helper will help you keep everything in once place so you can basically ignore minimongo. This is much slower to build and more complex but not much more than ajax reqs in a regular app. I think it’s also more performant due to batching.

i’ll try to get back to this tomorrow,
Cheers

@SkinnyGeek1010 thanks for your answer. Concerning the Meteor mixin for all the DB data, it would be cleaner to use one way or another. Not “mix” all different usages. I have gone through the official redux doc again and that brought me some lights, but am still keen to discuss. Have you tried upgrading your repo to use Meteor 1.2.?

road to redux…

A couple of weeks ago I was happily coding along in Blaze + Meteor + Iron Router. Then I read about the slow-down of Iron Router and the rise of Flow Router. After getting the hang of that I stumbled upon the huge blow-up of React vs Blaze etc etc. Naturally I felt defensive of Blaze and read through the hundreds of posts here on the forums.

I started becoming curious of what React was and what all the fuss was about. JSX seemed very odd to me too but I figured I’d at least give it a shot. The Youtube videos for JS Conf and ReactJS Conf that Pete Hunt gave finally clicked in what React was all about and I started liking React and even JSX. But quickly I saw the need for a way to manage the data flow.

That’s when I stumbled upon Flux. Apparently, like many others, I started writing my own Flux implementation using Facebook’s Dispatcher. I saw the futility of trying to maintain my own library and started looking for a decent implementation of Flux. None of them really worked well with Meteor concepts of reactive data until I stumbled upon this leaderboard github repo.

I took a look at Redux but it didn’t seem right… So I jumped into the Alt branch. Ahh, things finally made sense and worked together. And I LOVE the Chrome developer interface for viewing store and dispatches.

I could be happy with Alt, as you were in post #28 but I kept reading this thread and saw your migration to Redux (“Redux is the king of flux libraries” in post #45). I thought I’d tread in your footprints and try out Redux as well. I get Redux and it does seem simpler/faster to build up the reducers. Immutable state is cool tool.

the questions

I still like Meteor a lot and the concepts and build system but trying to fit Redux in is a little puzzling. So I have some questions, some of them being the same as previously mentioned on this thread.

  • In a more complex app, how would you handle minimongo, meteor reactivity, and state? This is exactly what @rdewolff mentioned in the previous reply. Is separating minimongo data and local state the way to go?
  • I’m used to the all packages approach. You mentioned your Webpack and ES6 modules method in post #47 but that it’s “kind of a hack to get it working”. Any examples on how you are using Webpack and ES6 modules?
  • Reducers can be split up into smaller functions, which is really nice. Should these smaller functions be collected together in Domains, like how plain Flux talks about Domains? Or should there be another Domain/Business-logic layer as well?
  • Does Redux prevent cascading actions? Or is the fact that the state should be immutable make that non-applicable?

I’m sure I will have more questions. Thanks @SkinnyGeek1010 for your work on this leaderboard example! It’s really helped me out.

2 Likes

I’m opting to use my flux-helpers package to essentially dispatch an action every time the collection changes. However, this is mainly to hedge my bets. It’s a bit more work but makes the entire frontend data layer agnostic from the framework. In a complex app I think the extra work is worth it.

The alternative is to use the mixin. This works, gets the job done, and doesn’t require any extra wiring. However, you’re very tied to Meteor and it will be extra work to switch to a non mixin method.

I’m used to the all packages approach. You mentioned your Webpack and ES6 modules method in post #47 but that it’s “kind of a hack to get it working”. Any examples on how you are using Webpack and ES6 modules?

I have this one which is similar to my current rig: https://github.com/AdamBrodzinski/meteor-webpack-react
There’s also another webpack project (kickstart?) that hides more of the webpack details for an easier experience (also a medium post which is great).

Reducers can be split up into smaller functions, which is really nice. Should these smaller functions be collected together in Domains, like how plain Flux talks about Domains? Or should there be another Domain/Business-logic layer as well?

I think so. It can be grouped however seems best for your app. The only reason for not using 1 reducer is that it’s harder to find the section you need w/o grep.

Does Redux prevent cascading actions? Or is the fact that the state should be immutable make that non-applicable?

Yea they’re batched within the same event loop I think.

Thanks @SkinnyGeek1010 for your work on this leaderboard example! It’s really helped me out.

No prob! glad it helps. Make sure you checkout the new Egghead videos from the creator of Redux too!:

1 Like

I’m assuming you meant "if you’re very tied…"
Do you think Meteor has a place in this Webpack,React,Redux,etc ecosystem? It seems like I have drifited very very far from my original Blaze/Meteor beginnings. Which I’m not opposed to. I loved the simplicity of Meteor and Blaze. The magic of it was very fast to write usable apps. But I do love the concepts of React, Flux/Redux, etc. Webpack, at least to me, seems like something I have to learn. I was actually quite at home working with package.js files. But I’m OK learning Webpack too. Meteor was a big departure from PHP for me. :smile:

I tried to clone your repo but it didn’t work for me. I jumped up to jedwards1211’s repo and that seems to be working fine for me. Not sure how your fork has drifted from that one. I haven’t yet looked at that other project you mentioned.

One question with Webpack. How do you separate client, server and both code? Are the files main_client.js and main_server.js files special in this webpack/meteor setup?

Thanks again. Meteor does have a truly awesome community.

1 Like

Ah, so I just meant that if your components are using the MDG mixin you’re app is very tied to Meteor and the tracker implementation. However, if your components are using Redux to get the data they don’t know or care about Meteor, they just expect props as data.

The major benefit here is that if MDG changes the mixin, stops maintaining it, or if it starts having perf. problems, you won’t be affected.

However, their easy use may be reason enough to justify the extra coupling.

I tried to clone your repo but it didn’t work for me. I jumped up to jedwards1211’s repo and that seems to be working fine for me.

Great, glad it worked! Mine might need npm 2… I think npm 3 needed a few extra deps. That repo was from an older pull request so Jedwards repo is the best to use.

One question with Webpack. How do you separate client, server and both code? Are the files main_client.js and main_server.js files special in this webpack/meteor setup?

Ah good question. So in normal JS apps using ES6 there is always one file that is the entry point. This file then requires another, and that could require another. This is how you end up with the bundle. If you don’t require a file, it never gets loaded into the client (or sever). So the client webpack config says to start at this main client file and bundle all imprted files. same with the server.

So the client has one bundle, and the server has one bundle. Each of these bundles are made by starting at the 'main_client.jsandmain_sever.js` does the same.

The default setup is an ‘isomorphic’ approach where all code is shared and a module doesn’t really care if it’s for the client/server. For example if the client never imports the publicaton file it will never get sent ot the client.

If it helps you can have folders like client, server, and both to organize this.

1 Like