Yeah that’s my understanding as well, even more so with HTTPS as far as i’m aware. I just meant less load on the server if you hypothetically compare HTTP requests on mutations with no websockets vs websockets and Meteor methods.
“Not going to break” is definitely good, but for me an important factor in picking a technology is whether it’s still growing and evolving or not. The main reason I’m considering migrating to Apollo is simply that it’s where MDG seems to be putting its focus, so even though pub/sub isn’t going to break I also feel like it’s not going to improve anytime soon.
So I don’t feel it’s fair to compare pub/sub and Apollo just on a current feature basis. One obviously has a much more promising future than the other, and people should be aware of it.
I’m on Meteor 1.1.
I have a ton of screens that are are just forms (inputs/dates/radio/checkbox controls) with a submit button. I’m using the aldeed stack: Autoform, Simple Schema, and Collection2.
For example, client side, reactive, conditional validation on the form? Maybe even using Simple Schema?
I’m trying to move away from Autoform and am thinking of embracing React these days, but wiring up reactive, conditional, client side validation done right is a real pain (and right now Autoform and Simple Schema handles this nicely with a little code). Add to this I don’t know React, and I’m in a real spot here.
Also, I thought Apollo/GraphQL was not ready for production apps?
I’m currently trying to rewrite “only parts” of my 70k loc main app.
From meteor (reactive stuff)/blaze to redux/react.
From my point of view, it’s hell.
Yes, you can rewrite only leaf of your UI in React/Redux.
But everytime you touch something, there is a dependency that is touched and need to be adapted.
I have a “long running branch” opened more than six months ago, and i don’t see the end.
That and the fact that previously working code is now in a state of “hope that works” (it was really difficult to write tests with the old paradigm so i don’t have any).
Moving to Redux/React – we loose the reactivity that we had with Tracker/Blaze right? Also, Apollo does not support reactivity either right?
Yeah I think this is going to be tough in general. Forms tends to be pain for me in React regardless of what i’ve tried.
I’ve also tried autoform and simple-schema and for just starting out… the API is huge and for me confusing. It’s made maintaining the forms a real hassle. Doing forms the more manual way is a bit of up front work but i’ve found it to pay off in spades later on.
For most forms in React I handle them exactly like I do in Blaze (note, also not saying this is the right/better way). I just write them out manually, give each one a name like firstName
. Then I use a little lib I made called parse-form to extract all the form name/values into an object. This object can run through a few validations in the click handler and then if passed, is passed into a Meteor method.
With React it’s really easy to take a block of markup from a bootstrap input item and wrap it into this (it’s basically just taking those arguments and plugging it into a more verbose set of html):
<MyInput
name="firstName"
label="First Name"
// looks at container error object and display an error if it's own `name` is present
errors={this.state.errors}
/>
// in form submit handler
var form = new ParseForm("#signup-form");
if (!form.firstName.trim()) {
const stateCopy = clone(this.state.errors);
stateCopy.firstName = "First Name is Required";
return this.setState(stateCopy) // return early if error, ui will self render err msg
}
Meteor.call("signupForm", form, (err, res) => {
// go to success page or display server error modal
});
The error step is optional and you can even punt that to jQuery if you’d like to imperatively attach an error class and message in the submit handler.
This is way more upfront work compared to autoforms but the upgrade path with this methodology from Blaze to React is really simple if the Blaze version is declarative. In an older Blaze app I used Session.set()
instead of this.setState
to keep it declarative.
The path to Apollo is then really simple because the Meteor method above is almost a copy/paste from the Meteor method to the Mutation. I just had to change the check
schema in the Meteor method to the GraphQL input schema which takes 5 mins once you know how it works. The Apollo core API has the same callback pattern as the method above.
If you have a lot of forms you could reduce boilerplate for the checking to something like this:
var form = new ParseForm("#signup-form");
const reqFields = ["firstName", "lastName", "email"]
if (!hasRequiredInput(form, reqFields, this.setState)) return;
if (!hasValidEmail("email", form.email, this.setState)) return;
// .... more validations
Meteor.call("signupForm", form, (err, res) => {
// go to success page or display server error modal
});
Lastly, you could automate a lot of the checks by moving error checking logic into the input and then use a central redux store to save errors, but the tradeoff is only worth it if you have lots of inputs to check IMHO. setState
is much more simple.
The UI is still reactive in the same ways Blaze is reactive with Session and local mini-mongo collections.
The database layer itself is not reactive in the same way (which is why it’s faster for high load). The reactivity is much more coarse in this way (using Blaze/methods as an example)
Events.someTemplate({
"click-update-user": () => {
Meteor.call("getUser", "user123", (err, res) => {
Session.set("pages:profile:username", res.name);
});
}
})
<template name="profile">
<div>
Username: {{getUsernameFromSession}}
</div>
</template>
This lets you either choose when to fire the update (as in the click handler) or you can even force to re-call the method every X seconds. In Apollo you can do this in a config to auto poll every X seconds when you really do need live data. Eventually GraphQL will support subscriptions so a DB like RethinkDB could stream in changes (as far as I understand it, maybe @sashko can confirm this?).
Thanks for this @SkinnyGeek1010.
Yeah, I made a big mistake by using autoform, I should have just hand-rolled them from the start. Also, it looks like I’m going to have to just make the move to React/Redux.
My main concern is getting the reactive conditional validation right. I need to start out with just one form, convert it to react, perform the reactive conditional validation (with error messages beside the controls), and after that I should be able to replicate that across all the forms (almost every screen has validation).
Forgot, I also have JQuery masking on some of the input controls, for example making for dates/phone numbers, etc. Will this work in React?
Any good videos to prep me on React/Redux before I start?
Also, I’m using Iron Router, do I need to move off of this before moving to React/Redux?
Also, If I move to 1.3 everything is going to break right? I might want to start the migration to React/Redux with 1.1?
Just curious how many inputs do you need to validate on a single form? I’m personally trying to depend less on Redux unless I really need to share state. Having a container component class that wraps a pure component view has worked out really well with cohesiveness. If you have lots of inputs with the same type of check you can always use an array to list input names and use the same type of check.
If you move that to redux each input will have to validate itself which adds a lot of complexity. I had a form with hundreds of inputs and lots of one off checks so it made more sense to go the redux route. It does have a cost though. You can then add in validations like <MyInput name="foo" required={true} validEmail={true} />
or a more terse <MyInput name="foo" required validEmail />
Forgot, I also have JQuery masking on some of the input controls, for example making for dates/phone numbers, etc. Will this work in React?
This should work great unless you have a controlled component, which I tend to not use as it’s very rigid.
Any good videos to prep me on React/Redux before I start?
Hands down https://learnredux.com (free too!) . Wes’s React course is worth it’s weight in gold as well.
Also, I’m using Iron Router, do I need to move off of this before moving to React/Redux?
I would do that last, then move to React router. You can have a blaze wrapper page like this that only renders the initial page (only perhaps have just a single div as opposed to the markup here)
If you haven’t watched this, it’s a must have:
Also, If I move to 1.3 everything is going to break right? I might want to start the migration to React/Redux with 1.1?
As far as I know if you upgrade to 1.3 everything will work as is (globals and all). Some packages may have issues if they haven’t upgraded to 1.3 but at this point shouldn’t be an issue.
Yeah that’s rough… I can relate. Re-writing problem areas in React could be a strategy as well. I’ve also tried writing ChimpJS tests before re-writing. Being able to execute JS in the console and test a result can be very helpful too (for example in a chimp test test for some UI stuff but also do a runJS(Meteor.userId()) === "u123"
to ensure the data is correct. But yeah testing in Meteor has been a bear.
Some forms have approximately 75+ inputs. Most are between 25-30 inputs. Most have common validations I have factored into external functions called within SimpleSchema – for example, if radio1 is selected, then input1 and input2 are required, else they’re not. Some are one-offs too of course.
Share state across forms or within a form (aka Template)? For the most part I use template state (Template.instance().state.get(‘someVariable’)), but I do share some session across templates, which of course I use Session.get(‘someVariable’) for.
What would take the place of template state in React?
Sounds like I should stay away from Redux to start then. I want to start out as basic as I can, and as I get more comfortable, I can move to more advanced techniques.
Great.
I’ll check these out, thanks. Egghead looks like they have a few courses on React/Redux. Also, Pluralsight has a few course on React.
Glad to hear it, I’ll stick with Iron Router to start.
Thanks for all the tips and advice.
Template state would be the this.setState({count: 1})
that can be used anywhere in the component. To read the state you use this.state.count
and it would return 1
. With React you can (and should be design) pass data down to children. In Blaze it’s a bit tough to pass template state down to children.
In React you can then pass this.state
down to children by doing this: <Child someCount={this.state.count} />
and then the child component can read it as this.props.someCount
. You can keep threading data downwards and those pieces will re-render whenever the this.setState
is called… updating all the UI below it.
If you need to pass data across to something a parent or sibling… you really can’t (hence 1 way data flow). You would need to store the state higher (App being the root generally) so that all children would get it. For the children you would need to pass them the function this.setState
because they have no way about knowing anything about their parents (as it should be). This is where Redux comes in. Instead of threading the data and setState down through many many layers, you can just use a connect
function to connect to a global setState
and it will pass that data in as props. You can think of it as Session with very strict rules on how to use/mutate data (to keep with 1 way data flow).
At any rate I would start here:
and when you run into this issue of sharing state to parents or deeply nested children, remember redux can help you out in this area. If it’s not helping you out you don’t need it.
Keep this article in mind for how to organize data fetching and presentation. This would have saved me countless hours of maintenance if I did this when starting (and using propTypes in the presentation component for loud errors when deps change/break).
Sounds very complex. May be it is better to create kind a FormStoreClass in terms of Redux? It is not a good idea to store form data into Template (or Component). You can add some class-level logic like “if radio1 is selected then radio2 should be disabled”
Moreover, guys, thanks to @SkinnyGeek1010, few months ago I started w Redux+Asteroid (means no Minimongo, Redux Stores, DDP). And very happy today. Redux is nice thing makes all your client-side data predictable.
And hell yeah Meteor is easy and a lot of fans worry about it could be complicated. But, if you are on the semi-large app w Meteor it is very-very complicated anyway, and it is right way to bring new things into Meteor. Thanks MDG!
While researching React I ran across this page where it states we can create react apps without configuration, what’s this all about?
I hope I didn’t overstate the complexity. A lot are more complex than my example, but most are if this than that – but there are a lot of them for sure.
I think SkinnyGeek was saying that if I have too much “store”, Redux will start to put a drag on the app is all.
If you need to pass around and store UI data about a template, outside of a global session, how else do you propose doing this outside of Template level sessions? I’m not using React/Redux at the moment.
I’m doing this with simple functions (no class needed). I pass in the field to check and what to check for and have relatively small code base that takes care of 80 percent of the validations.
I looked up Astroid after I read your post. Interesting. Astroid seems to just be a way to decouple the client from the server – we can use DDP, Minimongo and the rest of it if one likes. Why are you using it?
I’ve never understood why some say things like this. I really wonder what’s behind it sometimes.
Not to take anything away from React/Redux, but Blaze/MiniMongo/Tracker and the rest of it is so predictable on the client-side, I just smile sometimes. Bug fixes and maintenance are quick and easy. The application is so easy to build, predict, and develop for – it’s a dream. I’ve been very happy with this tech stack.
No, I’m thinking of moving away from Blaze (not necessary towards React) – and adopting React – not for technical/maintenance reasons at all.
Thanks for your feedback @mrzafod!
That’s great to hear! I’ve had horrible issues with Blaze maintenance several years ago. Part of it was using imperative solutions when a declarative one could have been used, as well as having reactive state everywhere. I think if I had to use Blaze I could make it 100x more maintainable now, using the ideas behind React.
While researching React I ran across this page8 where it states we can create react apps without configuration, what’s this all about?
FB released a new tool to run and build React apps without using Webpack. It actually uses webpack under the covers but you never configure it… just npm install && npm start
and start building. It’s what I had hoped MDG was going to do for the React ecosystem. They’ve managed to make it dead simple/fast to get a React app working
Cool, great to hear! I guess now that Apollo is out you could also transition to that pretty easily now if you wanted!
When I read the announcement page, I thought, the pitch sounded a lot like something the MDG group would announce.
Which brings up a question, when I learn React from all the sources you’ve linked to above, is there a reference somewhere about tying all this React experience into Meteor 1.4 (or any version of Meteor)?
In Meteor 1.4, all of the standard React code you’ll see online just works out of the box, with modules, build system, etc. That’s kind of the whole point of Meteor 1.3+, that it follows all of the standards of the wider community.
The React starter CLI tool is great so far, but does only a small fraction of the stuff the Meteor CLI/build tool does right now. Hopefully it gets more features over time!
Thanks. But how does/should React (or Redux) work with Meteor? For example, should (or can) I use Sub/Pub and MiniMongo queries to get/receive reactive data from Mongo like I do today with Blaze? And in my case a migration add-on question, can do said React migration in Meteor 1.1?
The reason I ask is, since I’m on Meteor 1.1 and Iron Router and use Autoform, I think I need to first migrate all my form-style screens to React while still on Meteor 1.1 (before making the upgrade to Meteor 1.4).