Elm vs Vue/React which one do you prefer to use with Phoenix, and why?

Well, it’s indeed meant to be humorous, because most of the arguments one sees around these kinds of questions really just boil down to personal opinion, which is no problem at all, hence my list of “valid” reasons to go with React, the problem comes when those opinions are “travestied” as being based on Reason and not merely an opinion.

As far as I can see this:

render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        <h1>Move the mouse around!</h1>
        <p>The current mouse position is ({this.state.x}, {this.state.y})</p>
      </div>
    );
  }

Is a particular form of “templating” language.
And sincerely I can’t seem to understand how it differs from having:

<template>
 <div :style="{ height: '100%' }" onMouseMove="myFunction()">
   <h1>Move the mouse around!</h1>
   <p>The current mouse position is ({{x}}, {{y}})</p>
  </div>
</template> 

With the exception that in a vue component I can place that in the html itself, which I would argue makes for easier reading, editing and understanding of how the DOM will be represented once the browser is done rendering it. (and you could always render the component in a JSX like style if you really wanted).

If you read the post to which I was referring I think you can see that most of what is written there is personal opinion, some of it wrong, yet I don’t feel insulted by the fact someone has written it…

1 Like

That is a common misconception. JSX in React is an XML representation (of parts) of the component instance tree. Your particular example only references components that translate directly to DOM elements - and as part of the reconciliation process, the instance tree will be reduced to a tree of DOM elements (their VDOM counterparts) - but strictly speaking a tag in JSX simply references a component - which may not in itself have a direct manifestation in the DOM tree (though it likely nests components that end up rendering something to the DOM tree).

1 Like

@peerreynders I’m not going to pretend I understood everything you wrote - and I’m also not super into the underlying implementation details of either Vue or React - but don’t they just do the same thing under the hood? Perhaps with an example of how they actually differ I could understand the differences.

This is a strange thing to say about web-development. But seriously, Vue is very little like Angular, other than the template directives, and the template directives are really not very important - but they are simpler and cleaner than JSX in my experience with both frameworks.

I would love for this to be true, but I’ve never seen a job advertise for Purescript. I know Slamdata uses it, have you seen other jobs out there?

In my opinion Halogen is the most mature Purescript framework and it has virtually no community development to speak of - there is no ecosystem. For example, is there a single widget library? If I look just at the Reagent ecosystem in Clojurescript, there are at least three different widget libraries or wrappers built up by the community. Its not hard to build stuff like this yourself but it sure feels like a waste of time.

1 Like

4 postings on FunctionalWorks right now, 2 of them from the same company, 3 of those explicitly saying “you would be working with …, PureScript, …” (they are Haskell and Erlang positions as a base) and one only mentioning that they’ve “drawn inspiration from …, PureScript, …”.

You must not be looking very hard if you can’t find any job listings for PureScript, to be honest. It’s not super hard if you try. It’s another matter to actually find one you’d be able to land, but to say that they’re too rare for you to even see just suggests that you’ve either not looked for them or you simply are out of touch with where and how to look. Though, to be fair, you could’ve literally just googled it.

(I only had to open FunctionalWorks and go to my dashboard to find two of the PureScript ones recommended for me, in fact, because FW knows I’m interested)

This is a strange thing to say about web-development. But seriously, Vue is very little like Angular, 
other than the template directives, and the template directives are really not very important - but 
they are simpler and cleaner than JSX in my experience with both frameworks.

I made a remark on what angular and vue have in common: those directives. Some thoughts:


edit: https://codeburst.io/80-of-my-coding-is-doing-this-or-why-templates-are-dead-b640fc149e22

Overtime, most template languages eventually reinvent practically every feature of a 
general purpose programming language.

Also: External DSL's

External DSLs on the other hand are like puppies, they all start out cute and happy, but without 
exception turn into vicious beasts as the grow up (Erik Meijer)
1 Like

You should have a look into what Ember is doing with templates. They make a pretty solid argument around the performance gains to be had by compiling to bytecode and taking the parsing step out of the initial render.

Clearly I haven’t looked in the right places; I never signed up for FunctionalWorks because they didn’t offer evidence on their homepage of anything of interest to me, and its impossible to browse listings without signing up, which is bizarre.

Looking in the usual places like Indeed and StackOverflow I can find jobs that have the word Purescript in them, but almost always in the “gee its cool, but we don’t actually use it here” type reference.

Yes I used to think thoughts like those. Then I actually used it and now I feel differently. YMMV.

I agree that this is usual, but I’d say it applies to most languages that are actually interesting. It’s either that or “You will be working with Java, Scala and [exciting language]” and what the listing doesn’t really spell out is that about 1% of the code is actually in this exciting language and the rest is just JVM boilerplate.

It’s too bad that they have this pattern. I never noticed it because I just signed up right away when I was looking for work at one point. They offer an excellent user experience if you do sign up. It’s very much tailored towards finding you opportunities, with emphasis on you ranking the languages you are interested in, etc…

When I was looking previously I found something like 4-5 positions that explicitly said that they had front-ends written in PureScript and two of those mentioned halogen specifically, though not really as a requirement.

If one is into Scala there are 160 listings on FW right now and in the case of Scala they actually put Scala in the position title, so it’s a good bet that you’d be spending most of your time writing it.

(For less meaningful reference, there are 38 Haskell listings and 9 OCaml listings, though a good portion of the OCaml ones list OCaml as an auxiliary language)

Given your familarity with Vue I suspect you know how you would use it to create the following trivial example.

So I will go forward to attempt to illustrate why I think viewing JSX “as markup” is misguided and limiting.

Personally I’m no fan of JSX but I’m not the first to feel that way.

Counter.js · GitHub
shows your typical introductory React custom class component. This style of component is sometimes referred to as a “vanilla component”. Vanilla components have their use and place but as such they don’t seem to be really representative of the type of components that are used in “sophisticated front-ends”. So I’m going to take this basic component and deliberately over-engineer it to highlight some other aspects that occur in applications with more complicated requirements.

Every component instance tree starts with a root:

// File: src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import ContainerComponent from './ContainerComponent';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(
  <ContainerComponent />,
  document.getElementById('root')
);
registerServiceWorker();

<ContainerComponent /> is JSX but it simply references a plain custom component (and it’s not some magical “app component”). It’s nature is such that it “assembles” a tree of lower level component instances, or in DDD terms it is an “Aggregate” of a larger whole. The render can be easily rewritten without JSX as:

ReactDOM.render(
  React.createElement(ContainerComponent),
  document.getElementById('root')
);

Again the name createElement is unfortunate because it evokes an association with the DOM Element object. React Components, Elements, and Instances hints that it actually creates something of a specification object that references a component constructor and a “properties” object (with child “specifications”) for a particular component instance.

So <ContainerComponent /> is simply an XML tag to reference the ContainerComponent constructor function - it’s not markup.

Moving on to the next piece:

// File: src/ViewComponent.js (ES2015 Module)
import React from 'react';

// functional (stateless) component
// is passed a "props" object
const ViewComponent = ({ value, increment, decrement }) =>
  <div>
    {value}
    <button onClick={increment}>+</button>
    <button onClick={decrement}>-</button>
  </div>;

export default ViewComponent;

It’s a simple ES2015 module that contains some JSX that looks a lot more like markup because of the familiar div and button tags. But just as before those are just references to some predefined React DOM components. It can be rewritten as:

import {button, div} from 'react-dom-factories';

const ViewComponent = ({ value, increment, decrement }) =>
  div({},[
    value,
    button({key: 'increment', onClick: increment},['+']),
    button({key: 'decrement', onClick: decrement},['-'])
  ]);
  
export default ViewComponent;

or even

import {createElement} from 'react';

const ViewComponent = ({ value, increment, decrement }) =>
  createElement('div',{},[
    value,
    createElement('button', {key: 'increment', onClick: increment},['+']),
    createElement('button', {key: 'decrement', onClick: decrement},['-'])
  ]);

export default ViewComponent;

Now lets gets some terminology straight:

  • The ViewComponent instance is the Owner of the div and button instances (and of value). Lot’s of sources refer to ViewComponent as the Parent which is incorrect (ViewComponent would be the parent of children which are passed in the props object - but this example ignores those, so if any are passed they simply won’t be rendered).
  • The button instances and value will be handed to the div instance as children (inside the div’sprops object). So [value,button,button] are children of div, while div is the parent of [value,button,button]. So with JSX the owner ViewComponent gets to declare the children of div by placing them in between the opening and closing tags <div></div>.

Now <button onClick={increment}>+</button> clearly has something that looks like an (onClick) attribute. The notation can be changed to <button {...{onClick: increment}}>+</button>, expressing that the properties of the {onClick: increment} object should be spread over the props object intended for the button instance. So these “attributes” are simply key value pairs for the props object.

const ViewComponent = ({ value, increment, decrement }) =>

shows what props look like on the receiving end. ViewComponent expects an incoming value for display and increment and decrement functions that are used to notify the owner instance (or something further up) when state changes are required. The props object essentially describes the runtime interface of the ViewComponent instance. Incoming data is simply delivered as values while function( value)s are provided as a means to move outbound data. In effect the ViewComponent instance acts as a distribution point for the prop-values among its nested component instances.

If ViewComponent was an electronic component the props property names would be equivalent to “contacts” or “wire terminals”, while the property values act like “wires” (or the information on those wires).

Now to the final piece of the puzzle, ContainerComponent:

// File: src/ContainerComponent.js (ES2015 Module)
import React, { Component } from 'react';
import ViewComponent from './ViewComponent';

// Based on:
// https://gist.github.com/gaearon/a9bbb73d57b6e4cc17d7b50807b62f9a#file-counter-js

// ContainerComponent initial state
const initialState = () => ({ value: 0 });

// action types
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

// action creators
const incrementBy = (n) => ({
  type: INCREMENT,
  payload: n
});
const decrementBy = (n) => ({
  type: DECREMENT,
  payload: n
});

// state updates
const incrementState = (state, n) => {
  const value = state.value + n;

  return { ...state, ...{ value }};
}; // use "spread in object literals" to update "value" in the "state" object.
   // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals

const decrementState = (state, n) => {
  const value = state.value - n;

  return { ...state, ...{ value }};
};

// reducer
const reducer = ({type, payload}, state) => { // takes action and state
  switch (type) {                             // to produce next state
    case INCREMENT:
      return incrementState(state, payload);
    case DECREMENT:
      return decrementState(state, payload);
    default:
      return state;
  }
};

class ContainerComponent extends Component {
  constructor(props) {           // ignores props i.e no communication
    super(props);                // with OWNER component

    this.state = initialState(); // i.e. give React the initial state
  }                              // for this particular instance
                                 // Everwhere else "this.state" is READ-ONLY
                                 // while "this.props" is always READ-ONLY
                                 // i.e. they are managed by React on behalf
                                 // of the instance.

  send(action) {                 // i.e. emulate ReasonReact.reducerComponent
    this.setState(prevState => reducer(action, prevState));
  }                              // setState "requests" a change of state
                                 // for this instance, i.e. state changes
                                 // asynchronously.

  increment = () => {            // function for nested component instance
    this.send(incrementBy(1));   // to initiate an action
  };

  decrement = () => {            // Using "Property Initializers" combined with
    this.send(decrementBy(1));   // "Arrow Functions" to avoid having to bind
  };                             // member functions in constructor
                                 // (if they are passed to nested component instances)
                                 // https://github.com/tc39/proposal-class-fields
                                 // http://2ality.com/2017/07/class-fields.html#initializers
                                 // https://reactjs.org/docs/handling-events.html
  render() {
    const {state: {value}, increment, decrement} = this;

    return <ViewComponent {...{value, increment, decrement}} />;
  } // https://reactjs.org/docs/jsx-in-depth.html#spread-attributes
}

export default ContainerComponent;

// See also:
// https://reactjs.org/docs/lifting-state-up.html#lifting-state-up

A lot of code, yes. But as I said it is deliberately over-engineered. But it’s still a just a plain ES2015 module. Interestingly all of the rendering to the browser’s DOM is delegated to ViewComponent in:

    return <ViewComponent {...{ value, increment, decrement }} />;

Again the JSX can be gotten rid of with:

    return React.createElement(ViewComponent, { value, increment, decrement } , []);

Dan Abramov discusses container components in Presentational and Container Components. So all this code is simply infrastructure to support the operation of the nested, lower-level component instances - it’s a component and while the instance may hold data that gets rendered to the browser’s DOM, it’s not directly involved with any DOM elements in the browser - the components responsible for DOM elements are div and button under ViewComponent.

This example can be pushed even further by removing ViewComponent from ContainerComponent and adding a render prop to ContainerComponent:

// File: src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import ContainerComponent from './ContainerComponent';
import ViewComponent from './ViewComponent';
import registerServiceWorker from './registerServiceWorker';

const render = (props) => <ViewComponent {...props} />;

ReactDOM.render(
  <ContainerComponent {...{render}} />,
  document.getElementById('root')
);
registerServiceWorker();

or

// File: src/index.js
import React, {createElement}  from 'react';
import ReactDOM from 'react-dom';
import ContainerComponent from './ContainerComponent';
import ViewComponent from './ViewComponent';
import registerServiceWorker from './registerServiceWorker';

const render = (props) => createElement(ViewComponent, props, []);

ReactDOM.render(
  createElement(ContainerComponent, {render}, []),
  document.getElementById('root')
);
registerServiceWorker();

and

// File: src/ContainerComponent.js (ES2015 Module)
import { Component } from 'react';

// ...

class ContainerComponent extends Component {
  // ...

  render() {
    const { props: {render}, state: {value}, increment, decrement } = this;

    return render({value, increment, decrement});
  }
}

export default ContainerComponent;

So does <ContainerComponent {...{render}} /> (i.e. JSX) have anything to do with markup?

  • It’s XML used to declare the component instances in an instance tree.
  • The tag name identifies the component constructor function.
  • The collective “attributes” on the tag define the component’s props - the component’s “runtime interface” and defines how that “runtime interface” is “wired” for this particular instance.
  • The tags between the opening and closing components declare the child component instances for this particular component instance.

Simple React Patterns: Dealing With Side-Effects In React explores some other common React patterns in use.

Now container components aren’t a universal thing:

People are reading way too much into Presentational vs Container components divide. Almost regretting I wrote that.

Container components are a good place to put strictly local logic and state to keep it out of the view component(s) but at the same time a view component could easily nest a one or more lower-level container components.

Putting state in container components can by used to avoid introducing Redux into an application.

You don’t need a single source of truth for everything. Just make sure you have a single source of truth for any particular thing.

See also: You might not need Redux.

Reusablity is often used to justify container components - but I think that is just falling into the old OO trap. Good boundaries are always important irrespective of reusability concerns in order to clearly define what exactly passes into and what passes out of the boundaries. Selecting the right boundary is rarely easy - it takes practice, sometimes lots of it.

FYI: David Nolen (ClojureScript, Om Next) talking favourably about React.

Seems some people think containers could be a good idea in Vue: Structure a Vue.js App from Containers and Components.

See also JavaScript Report: How Is React Different from Vue?.

7 Likes

First, thank you for taking the time to write this throughly explanation.
I understand that JSX is not a “templating” language, what I’m arguing is that the overhead of learning how it works is similar to understanding how vue templates work because this is the argument that I hear the most - “it’s just plain old js you don’t need to learn a DSL…”. That’s not true.

Given that Vue itself can render JSX (you simply don’t because, well, it’s way more verbose and arguably harder to understand immediately what is the end result, specially if you have a lot of it) and that all templates are resolved to render functions themselves I would say that they’re pretty similar in that regard, where the “templates” in vue can be seen as “syntactic” sugar for the manual callouts to render - underneath they will do the same they just save me all the boiler plate code and in turn give me a neat organisation for my code. In fact when you instantiate a Vue instance you have a render property, where you use createElement and either pass a dom element specification, or, pass a component.

In a JS file:

import socket from './shared/socket'
import Vue     from 'vue'
import Vuex   from 'vuex'

import main_store  from './store/main_store.js'
import tree_root     from './views/tree_root.vue'

import '../css/app.scss'

Vue.use(Vuex)

const store  = new Vuex.Store(main_store)

new Vue({
        el: '#tree-root',
        store,
        mounted: function() {
            store.dispatch('get_user')
        },
        render: function(createElement) {
            return createElement(tree_root)
        },
        destroyed: function() {
            unsync()
        }
    })

This will render a dom representation of tree_root, replacing everything inside the element #tree-root with the result of that render call. This tree_root component can be a single file component (but it can also be JSX, or a createElement spec), inside this component I have all my code neatly organised in 3 sections (although 99% of the time I don’t use the styling section, but you can, and you can scope it automatically as well), one is the template section, which allows me to have things like:

<template>
 	<div id="tree-root-wrapper">
   		<a-component some_prop="literal_string" :another_prop="any_js_expression"/>
   		<b-component/>
		<h1 class="title" @click="a_filthy_directive" @key.up.enter="another_one">Something</h1>
		<p :class="[ 'a-literal-class', aJSexpression, { 'some-other-class': truthyOrFalseJSexpression } ]">{{a_Prop}}</p>
                       <c-component v-if="truthyEvaluator"/>
                       <d-component v-else>
	</div>
</template>

(although I mentioned props I seldom use them, besides when using some lib because they require it, and even then usually the values I feed the props with come from a vuex store)

And each of these components, because they’re fractal, can render its own tree and that will substitute the component call in the template.

Then a JS part, which allows me to have things like this:

<script>
import { mapGetters } from 'vuex'

export default {
    name: 'games-index',
    data() {
        return {
            message: "",
            password: "",
            selected_game: false,
            tome: "",
            show_create_warning: false
        }
    },
    computed: {
        ...mapGetters([
            'messages',
            'games',
            'user_id',
            'open_game',
            'duel_start',
            'timer'
        ])
    },
    methods: {
        send_message() {
            this.$store.commit('new_message', this.message)
            this.message = ''"
        },
        prepare_join(game) {
            this.selected_game = game
        },
        //.....
    }
}

Where the computed properties are just references to a Vuex Store getters. In this case it’s only a top-level store, but you can namespace it and then use:

...mapGetters({
     'name_I_want': "namespace_level_1/namespace_level2/getter_name"
})

Or

...mapGetters('namespace_level_1/namespace_level2', { 
   'name_I_want': "getter_name",
   'name_2' "another_getter_on_the_same_namespace"
})

This is syntactic sugar for mapping a property in your component to a getter in your store. Similarly you have mapActions for async dispatches and mapMutations for mutations (commits) that well, mutate the state of your store. The async handlers can also themselves perform a sequence of mutations, call other actions, getters or access the state. You can explicitly define and express those boundaries through name-spaces and handlers, although there’s nothing forcing you to do it.

But if you don’t want to use the mapping helpers, you can write something like this too, where you call the store without the sugar:

methods: {
       close_game(id) {
            this.$store.commit('close_game', id)
            // some people will argue that this is bad, this <- refers to the vm instance and not the component and not the component scope alone - I argue this allows for a great deal of flexibility, and again, the boundaries are what you make of them
        },
}

Now I can use everything I define in methods, computed, data, etc inside the component. Plus I can share these from the top level of the instance to all the children components through mixins. And I can override them individually in the components.

This to me makes for a very readable structure. Do you have to invest some time learning it? Yes although I would argue that less than React to use to good results - because I did look into react before vue, and sincerely it never clicked while Vue did almost immediately - in the end it’s a few keywords you need to learn, and they’re very familiar.

Perhaps if I had started with React it would make more sense to me than Vue. I’m also don’t agree with purist arguments - while I agree that understanding the underlying concepts is important - I can’t really just use a tool because it’s “purer” if that comes at extra mental strain to execute to no significant benefit while having its own trade-offs and worse parts. Now I agree that probably if you write React you’re better equipped to write good JS in case React goes away, than if you write Vue and Vue goes away, because vue is a bit more magic. At the same time, we use frameworks so that we don’t need to re-invent the wheel. I like the wheels they designed in vue - and given that if react goes away you will still probably not be able to replicate it alone by JS yourself, the point is kinda moot.

I’ve written (and I’m still writing) a quite complex app, with several different bundles in Vue (some with ~= 2000lines between templates, js and several namespaced stores - not counting styling) which interacts with an Elixir backend through Phoenix Channels and I’m very happy with the setup. It’s actually quite sane to read, change and expand.

This is a possible store definition
main_store.js

import axios  from 'axios'
axios.defaults.headers.common['Accept'] = 'application/json';
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.withCredentials = true;

const state = {
    socket: false,
    csrf: false,
    user: false,
    user_channel: false,
    game_channel: false,
    pods_channel: false,
    axios: axios,
    loaded: false
}

const mutations = {
    set_csrf(state, token) {
        state.csrt = token
        state.axios.defaults.headers.common['X-CSRF-Token'] = token;
    }
}

const actions = {
    request({ state }, request) {
        return state.axios(request)
    },
    get_user({ state, commit, dispatch }) {
        dispatch("request", {
            method: "get",
            url: "/identify"
        }).then(response => {
            //commit
        }).catch(error => {
            //log error & notice
        })
    }
}

const getters = {
    user(state) {
        return state.user
    }
}

export default {
    state,
    getters,
    actions,
    mutations,
    modules: {

    }
}
// @returns {VNode}
createElement(
  // {String | Object | Function}
  // An HTML tag name, component options, or async
  // function resolving to one of these. Required.
  'div',

  // {Object}
  // A data object corresponding to the attributes
  // you would use in a template. Optional.
  {
    // (see details in the next section below)
  },

  // {String | Array}
  // Children VNodes, built using `createElement()`,
  // or using strings to get 'text VNodes'. Optional.
  [
    'Some text comes first.',
    createElement('h1', 'A headline'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
)

And lastly JSX makes me think a bit of how I used jQuery, $('#el').append($("<div class="+variable+" onClick="+clickFun()+">...</div>"))

1 Like

Big fan of Vue and Phoenix. Actually, bigger fan of Nuxt (SSR Vue) talking to a headless GraphQL Phoenix API via sockets; which is what I used for Edgewise (https://edgewiserealty.com).

3 Likes

There is very little to JSX. Many people use it by choice (because it gives them the warm, fuzzy markup feeling) while others simply fall in line to follow the convention that seems to have been adopted by the majority. JSX is just about Components, prop values and children - that’s it. Personally I never felt JSX added much value - but then again semicolons never bothered me in JavaScript either. In Clojure/ClojureScript I was perfectly happy to use hiccup for rendering HTML. In Elm using straight functions made a lot of sense (the arguments being one list for the property/attribute values and another list for the children).

When it comes to templating languages I never understood the appeal of Jade (or Pug) - I was under the impression that template markup was supposed to “look-and-feel” like HTML.

Now Vue’s template language on the other hand is a lot more complicated and truely classifies as yet another thing you have to learn. While it starts out looking like good-ole HTML,

  • there are the Vue specific directives (and short forms) and the proper way to use each of them; (and understanding subtleties like v-if vs v-show).
  • special tags like slot, keep-alive and how they work in concert with the rest of Vue.
  • and all this is just ceremony to ultimately transpile to a JavaScript render function call!

just save me all the boiler plate code and in turn give me a neat organisation for my code.

I think that some “boilerplate” can be managed with ES modules and the perception of Vue requiring “less” may be indicative of it having an opinion and it’s advocates sharing that opinion. React leaves you with the tyranny/paradox of choice - and the responsibility to manage the “opinion” that you choose (which also implies that you have room to choose poorly).

The best argument I’ve seem for needing a template langauge is to be able to work together with web designers who are used to working with HTML. Seems the current solution in the React space is to define all the markup related (view) components as functional (stateless) components (using JSX) and then to have designers style them in storybook.

I did look into react before vue, and sincerely it never clicked while Vue did almost immediately.

I suspect React only clicks with people who approach UI solutions from the rendering perspective. If you have familiarity with a templating based approach like EEx you would be predisposed to feeling that templating is a requirement and therefore you would lean towards something like Vue. React didn’t click with be either but I kept digging because om, reagent, re-frame and thermite use it - I figured there had to be a reason why.

Ultimately React is a bit lower level than Vue and therefore more work for the developer who has to figure out what the best way to use it for a particular UX problem is. Vue is more opinionated while covering a lot of the popular use cases.

I’m also don’t agree with purist arguments

I don’t think it’s about purity but more about explicit, visible, traceable flows of data.

Ultimately Vue’s API seems larger and more complicated and while the reactivity system isn’t particularly complicated, one has to be aware how it works (but React’s shouldComponentUpdate has its quirks too).

Because of React’s “simpler API” it is usually more work for the developer to determine how to use it effectively. (If you are Facebook averse and don’t need native there is always Preact and Inferno (JavaScript Report: The Best JavaScript Frameworks You’re Not Using)).


LispCast: React: Another Level of Indirection (2014-01-01)
6 Things Reacters Do that Re-framers Avoid

dotJS 2017 -Adrian Holovaty - A framework author’s case against frameworks

1 Like

I agree, you do need to learn it to use it, the documentation is small and it’s both progressive in implementation and concepts. I usually like templating languages, specially for server side html, like slim, because they clean up the view files and make them much clearer (and more like a program declaration set by indentation) but funnily in vue I don’t, because I have all the other markup (directives, etc) to use on the elements that stripping them of their tags and delimiters makes it less readable (I might need to give pug another go sometime, perhaps it was just b/c of being unfamiliar with vue at the time).

The following aren’t just interesting because of the comparisons but because of how the technologies are compared.

Choosing a Javascript Framework in 2017 (2017-03-23)

  • Bias: Ember
  • Others: React, Angular 2
  • Dave Bouwman remarks that in his opinion Ember has found all the right “seams” (i.e. selected the correct boundaries).

NDC Oslo 2016 - Choosing a JavaScript Framework - Rob Eisenberg (June)

  • Bias: Aurelia
  • Others: AngularJS, Angular 2, Ember, Polymer, React

Now while Vue.js isn’t part of these comparisons it should be clear where it fits in - it is a framework of the minimalist persuasion - so comparatively speaking there should be less to learn to get going.

I personally much prefer the Vue templating syntax over pretty much anything else; especially JSX. I really don’t think it takes much to “learn” at all. I actually like directives, as it’s far less verbose than other templating languages. You don’t need to know much of anything about Vue, to intuitively understand what’s going on here:

<ul class="thumbnails">
  <li v-for="image in images" :key="image.id" class="thumbnail">
    <img :src="image.url" :title="image.title" :alt="image.description" />
  </li>
</ul>

I appreciate the intuitiveness of that syntax, for the same reasons I appreciate the intuitiveness of Elixir. The fact that a designer also understands that is bonus points.

I would argue slots are worth the time to learn (and let’s be honest, it doesn’t take a PhD). For example, this uses a custom modal component as a wrapper where the dialog content is a slot:

<Modal>Nice!</Modal>

If that looks simple, that’s because it is. The “hard” parts are abstracted away into the parent component; creating reusable components that are inline with where the standards specs are with webcomponents / slots. For instance, you could swap out that <Modal /> Vue component with a Stencil component.

I use slots in custom <Panel />, <Modal />, <Alert />, and <Snackbar /> components (among others).

This is JSX equivalent…

<ul className="thumbnails">
  {
    images.map(image => 
      <li key={image.id} className="thumbnail">
        <img src={image.url} title={image.title} alt={image.description} />
      </li>
    )
  }
</ul>

<Panel/> <Modal/> <Alert/> <Snackbar/>

It looks the same… but no directives, and more functions. I don’t like directives, it corrupts the html markup imho.

And composability is also present in React. Having a custom library of components You just drop in is not Vue specific.

What I prefer in React is being cross platform.

<View>
  <Text>Hi!</Text>
</View>

This code works on IOS and Android…

I think an argument can be made that both are “corrupting” the HTML (eg. className).

IMO, that doesn’t look the same to me; that looks like 50% more code to accomplish the same thing (if you combine the curly braces / parenthesis). And that compounds as you add more logic. For instance, even just a little conditional rendering:

<template v-if="userIsLoggedIn">
  <ul v-if="images.length > 0" class="thumbnails">
    <li v-for="image in images" :key="image.id" class="thumbnail">
      <img :src="image.url" :title="image.title" :alt="image.description" />
    </li>
  </ul>
  <div v-else class="no-images">Sorry, no images yet.</div>
</template>
<button v-else @click="onLoginClick">Log in to view images</button>

But, if JSX is your thing, you can actually use it in Vue.

Definitely a valid point about React Native. The Ionic team has been working on Vue Native, but it’s still very early. It really hasn’t been an issue for me, but if being able to write native apps using JS is a business need, then React is a solid choice there.

It’s true it depends on use case… and personal taste.

For information, class and for are js commands, so className, and forHtml are JSX equivalent. Those are the only 2 attributes that need to be translated.

And I needed to make a mobile client for a Phoenix backend.

v-if is equivalent to

{ 
  cond && <div>true</div>
}

and v-if v-else

{ 
  cond ?
  <div>true</div> :
  <div>false</div>
}