Why doesn't MDG just adopt Vue.js and forget about React vs Blaze?

Just want to point out that in the Sideburns issue I did mention that I have some other work to wrap up before looking deeper into the work you have been doing.

Fine, I’ll settle down. I already feel more heard today on this stuff than any other time since the initial announcement. I should have more code to submit toward this aim next week.

3 Likes

I absolutely love VUE.

My programming journey started this year, with Meteor. Blaze is easy to pick up and I would argue Vue is only slightly more challenging. Vue gives me the power and organization I want from React but with the excitement and beauty I found initially with Meteor and blaze. I truly hope the integration between Vue and Meteor increases over time.

The only issue I have with Vue is occasionally missing a small code adjustment to make Meteor happy. Does anyone know of an article that goes over the basics and/ or healthy practices of integrating Vue with Meteor? Also just want to thank Laracasts, and Level Up Tuts for getting me excited to learn programming.

1 Like

Vue actually integrates easily already. There’s a package on atmosphere for it, and here’s a little video on it. https://www.youtube.com/watch?v=vsqBue6bM9Q

2 Likes

My view on Vue:

Getting Started

  • Hello World
  • Two-way Binding

(stopped there)

1 Like

Two way binding is evil. That’s why programmers have to do it themselves. Otherwise it’s too confusing. This is clean and easy to follow:

var Message = React.createClass({
  getInitialState: function() {
    return {message: 'Hello World'};
  },
  handleChange: function(event) {
    this.setState({message: event.target.value});
  },
  render: function() {
    var message = this.state.message;
    return <input type="text" value={message} onChange={this.handleChange} />;
  }
});

Now look at how confusing two-way binding would be:

var Message = React.createClass({
  getInitialState: function() {
    return {message: 'Hello World'};
  },
  render: function() {
    return <input type="text" bindValue={this.state.message} />;
  }
});
4 Likes

How come it is confusing? In the context of React or generaly?

The problems with two way binding happen when a lot of logic becomes encapsulated within the data binding engine. For example, should a text field be converted to a number or not? Now you’re either reading the type attribute of the input field, or you’re adding an extra attribute to the input to add additional information (this is the Angular style), or you need a callback to change the value before it’s saved to the model. I feel like in super basic use cases data binding makes for a nice demo where you don’t need to write any JS code to make stuff happen, but as soon as you need anything that the designer of the data binding system didn’t think of, you need to add additional options or work around the system.

At the end of the day, you often end up with a whole new language to learn, for example Angular’s ngModel directive: https://docs.angularjs.org/api/ng/directive/ngModel You need to learn about the entire API of the ngModelController to use this feature: https://docs.angularjs.org/api/ng/type/ngModel.NgModelController

In the React/Blaze model where you have explicit events, you have to write a bit of extra code up front, but at least it’s all in a language you understand (JavaScript) vs. a new meta-language of data binding that comes from a framework.

4 Likes

It’s not confusing at all. It’s completely obvious. But it’s problematic.

The reason it’s problematic is because you lose the old value for the field in your model. On insert, that’s fine–because there is no old model. But the reality is probably 75% of the time you are in fact updating models. So the 2-way binding can only hold the state for the latest changes, not the old value. 99% of the time you want the old value. Perhaps if the new value is incorrect, or if you want to compare to the old value for whatever reason, etc.

So basically 2 way binding is basically useless–when you can just do something like model.populate() which will suck out all the values from, say, AutoForm, and populate your model. Or model.populateField('name') OR: model.field('name') if you don’t want to replace the old value. In short, it’s one command to get all the values out of the form–why do you need the form to automatically populate your model on keyup? You don’t. It hurts you if you are trying to do anything more than a basic example, like what was on the old Angular homepage which is meant to make you go “ooh” and “ahh” but have no practical purpose.

I might agree to this if it weren’t for JSX and how it’s ruining markup and essentially taking front-end UI devs out of the picture. Angular’s (and somewhat vue’s) models may make HTML look ugly, but not nearly as ugly and problematic as jsx.

That’s exactly why the plan of migrating to React includes building templates for React. Then I would say you get the best of both worlds. (Even though I personally prefer JSX)

1 Like

It’s not confusing. I didn’t include the /s at end. There is no value in having developers write needless boilerplate code for no other reason than “the framework requires it”.

But what if I need to do an extra X when Y happens?

In those cases you write the necessary code. Plain and simple.

But you then need to know the name of the bind!

True, but that’s also true for React as well. In React you have to know that you have to use onChange and that it works differently than the browser’s regular change event.

But Angular is a monster and it uses data bindings

Just because Angular has a huge API surface and uses data bindings doesn’t mean data bindings are the cause of it.

At the end of the day a binding is just a shortcut. Nothing stops you from writing the following Blaze-like code:

<body>
  <input id="name" type="text">
</body>
Template.body.viewmodel({
  name: '',
  events: {
    'input #name': function(event) {
      this.name( event.target.value )
    }
  },
  autorun: function() {
    var name = this.name();
    $("#name").val( name );
  }
})

Or the following React-like code:

<body>
  <input id="name" type="text" {{b "change: updateName"}} value={{name}}>
</body>
Template.body.viewmodel({
  name: '',
  updateName: function(event) {
    this.name( event.target.value )
  }
})

But why would you if you can just write:

<body>
  <input type="text" {{b "value: name"}}>
</body>
Template.body.viewmodel({
  name: ''
})
2 Likes

@sashko @faceyspacey @manuel ok, thank you for clarification. Still some lose ends, but will come back with some extra findings :smile:

In reply to this topic in general, not just Evan’s post,

I am presently studying Vue.js.
I searched for this post thread because I am wondering (like others): Is there something I miss if I do not use React, but use Vue? I feel everything about a component should be in the same file.

I am looking for such UI tool because Meteor lacks:
-a safe and integrated way for managing housekeeping variables in a DIV (such as holding the previous value);
-a way to communicate between page parts (values and messages);
-beside the object structure that is also a plus for reusability.

-IMPORTANT: The most minimalistic/nonverbose syntax for accessing an element.

VUE seems the missing thing in Meteor (in my POV) in all these points.

I did not read well the present thread, and I am still questionning the necessity to continue learning React, and see that VUE has an impressive base of features.
(again, in my POV)

Many js tools do nice things in their way because they do not run with Meteor paradigm in mind. (such as generating a dropdown list). My point here is that, when we know Meteor (and I am a beginner), It feels like: Well, in meteor, it is natural, just do it the meteor way, without learning that other implementation that does not know about reactivity, templating, etc.

With Meteor and Vue, do we really need React?!

P.S. (edited) That thread’s title was also in my mind for a while (before I find this thread), and maybe in many others’ mind. Is it so creasy?

2 Likes

Vue can do two-way binding, it’s not enabled by default. It’s quite flexible.

The way to build Vue apps, emphasized in their docs is actually a uni-directional data flow in which data flows from the parent component to child components. However, you can have two-way binding to any degree that you want, or don’t want.

I have just started playing with Vue.js. I’ll report back when I have a verdict. But so far, it seems awesome.

2 Likes

No offense, but people who avoid two-way binding like a plague in general don’t really understand what two-way binding is.

First there’s the <input> box two-way binding, which is just syntax sugar for

  1. one-way bind its value to the state;
  2. handle onInput or onChange to update the state.

So Vue’s form bindings are basically sugar for simplifying this - even React has an official equivalent. And it’s totally optional; nothing prevents you from doing the one-way bind + event handler dance, if that’s more of your thing.

I don’t really see any point in avoiding form two-way binding, since the underlying model is still “state-driven view” - the source of the truth is the state underneath.

On the other hand, there is the concept of “two-way binding between scopes/components/models” etc., where it is in fact holding two pieces of state in separate places and trying to keep them in sync. This is what we have generally agreed to be a bad pattern and have stayed away from. In Vue the data flow between components is one-way by default. And because Vue separates the component from the state they observe (components only proxies to the state instead of owning it), the state tree can be completely externalized from the components, turning your app into more of a Flux-like architecture. (See vuex)

Next time when you evaluate a technology, try to understand what it really is - don’t shun something just because you’ve been hearing “two-binding is evil” without actually understanding the reasoning behind it.

12 Likes

Sorry if my comment sounds a little bit offensive. I have nothing against Vue.js or how it works. If you do understand it deeply and have no problem dealing with it, then you should use, no questions asked :wink:

Thanks for this clarification @evanyou. Two-way binding (like too many things in our industry) has become a catch phrase, and the nuances of it aren’t really understood.

Also thanks for bringing vuex to my attention. I’m planning on using redux to manage my app state, but if vuex will provide smoother integration with Vue.js that would be great. Will check it out in the next day or two.

1 Like

Agreed. 2 way binding to a model returned from Collection.findOne(), for example, means you lose the previous value for a field while the user types in an input, which you may need if the new value doesn’t validate and for various other comparisons you could make.

If you are using collection models directly with your form, as in @aldeed 's AutoForm, 2 way binding is nothing but hype and syntax sugar that will in fact mess you up. It’s why AutoForm doesn’t do it. But if it’s bound to component state, as @evanyou explains (and as @manuel 's ViewModel does), it’s fine and certainly an added bonus for that use case.

That said, when you aren’t using tools that closely map collection models to forms (again like AutoForm, or whatever will emerge in the React or Vue worlds), and instead are using 2-way-binding component state-based tools (like ViewModel or I assume what’s being talked about in Vue.js) you are forcing yourself to go through additional steps–boilerplate–to wire the form elements to “state” to a Meteor/Mongo model coming through Tracker and (getMeteorData or TrackerReact). The react world advocates more explicitness, more boilerplate, and repetition to achieve better debuggability and reasoning about your application in preparation for when it passes a threshold of complexity. To be sure, it’s smart. But, in comparison to the immense amount of automation Tracker + Minimongo provides, and until that point (that your app reaches “Facebook level complexity”), having to do all that extra work is absurd:

  • to go from Redux actions
  • to Redux Stores
  • to your components
  • to your component’s state
  • and while you’re at it retrieving models from getMeteorData
  • to form elements
  • back to component state
  • and finally back to updating/inserting your model

2 way binding between form elements and state automates only like 2 links in that long chain. Using Tracker + Autoform and Minimongo reduces all that to basically one step: embed a form and pass it the return of Collection.findOne(). Well 2 steps–since it doesn’t do 2 way binding (and you wouldn’t want it to)–then in event handlers you overwrite the previous values in the model or perhaps use previous ones if new ones don’t validate.

Minimongo (/w Tracker) is basically Redux’s "Single State Atom"+:

  • State all stored in one central decoupled place.
  • automated action creation (insert/update/remove/etc)
  • automated component subscriptions to stores (Tracker-based reactivity)
  • deep state querying capabilities
  • easily snapshottable–it just hasn’t been done yet (that i know of)

Not that some Minimongo+Tracker+Redux perfect combination on the horizon won’t be better (I’m looking forward to this)–just let’s not forget all that Tracker+Minimongo really gets us. In addition to tons of appropriate automation, it in fact gets you more performance than pure React+Redux for many things: it means smaller branches of your component tree need to re-render; only the smallest portion of the tree that depended on a reactive datasource. That’s as opposed to state functionally trickling through many components as props, forcing them to all re-render as it goes. In short, sideways data loading lets you easily reduce re-renderings only to affected branches in the component tree, no matter how deeply nested they are.

There are a lot of benefits to Meteor’s original Tracker-based approach–from performance in many areas (not all) to orders of magnitude less boilerplate code. As it is with everything, there is no clear winner–just better tools for certain challenges/goals. There are still many things Tracker+Minimongo is King for. We’d be remiss to leave it behind. Forms + Models (as in AutoForm) without 2-way-binding is one of them. To me, proxying through “state” before I put my data in a model and save it (or directly insert/update it) is just an annoyance–an unnecessary extra step or 2 or 3.

2 Likes

Not sure I clearly catched your point. Although the example of modal popup helped me see a good case for 2way binding: an OK button that will close the modal window. Here, it makes sense to use 2way binding of a button that will toggle a state for showing or not the modal popup.

On the other hand, YES!, one reason I was looking for a thing such as Vuejs is to be able to manage div related variable and one of these being the old value (before change, so to see if the value has changed) so I can evaluate an update/query to the DB, because I do want to avoid a full document rewriting. (I feel unsecure doing such update in a document), although maybe MongoDB, is doing anyway a full rewrite of the document in a new version of it.