ddraper

Vue vs React (initial impressions)

Blog Post created by ddraper on Jan 10, 2017
This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.

 

At the end of my last blog post I'd failed to make use of my alfresco-auth-router NPM package with the React "create-react-app" CLI. Instead I'd configured an http-middleware-proxy to route API requests (including those required for authentication) via a local Alfresco Repository.

 

The main difference was the approach to creating the application. I could just as easily as built my React project with a custom Express server that made use of the alfresco-auth-router but I wanted to experiment with the app building tooling provided for each UI framework. You can find the state of the React project at the time of writing in this GitHub repository by checking out this tag.

 

The "create-react-app" CLI is very much geared up to building Single Page Applications (SPAs) to it was necessary to use react-router to ensure that only authenticated users can access the Alfresco data. Again, this approach could have been implemented in Vue if necessary, in fact at some point I may go back and experiment with vue-router to see how it compares.

 

With authentication handled in both Vue and React applications it was now a case of building out my simple application for browsing "Company Home" in the Alfresco Repository. My intention was to implement the same component structure in both frameworks.... essentially a List component that contains Breadrcumb, Toolbar and View sub-components. 

 

As an aside I think that this is one of my main regrets about the way in which I implemented lists in Aikau. I had not foreseen the data down / events up model that is now becoming so popular and opted for a pub/sub model (although this does offer some advantages).

 

A better model is that the list manages the state and all state changing components (including pagination and breadcrumbs) are included within the list such that events can bubble up out to the list. I think that this fits with the model described in this post.

 

Both Vue and React have issues in this area in that... whilst Vue offers the ability to emit custom events these only go from child to immediate parent (and do not bubble) whereas React doesn't offer custom events at all. Instead the pattern for React is to pass callbacks as properties to child components (as described here). This presents an issue with deeper nesting of components - one suggested solution for React is described here (although I think this creates stronger coupling which should be avoided).

 

The other major difference is in how iteration is handled. Vue takes a very similar approach introduced in the original Angular library to provide an custom HTML attribute "v-for" to iterate over elements whereas React makes use of JSX to use a have a JavaScript loop to provide the iteration.

 

Vue.js:

<ul>
   <li class="components-lists-ListView__item"
       v-for="item in list.entries"
       @click="navigate(item, $event)">
{{item.entry.name}}</li>
</ul>

 

React:

render() {
   return (<ul> {this.props.list.entries.map((entry) =>
      <li onClick={() => this.props.navigationHandler(entry)} key={entry.entry.id}>{entry.entry.name}</li>
   )}</ul>);
}

 

I have to admit that I preferred the Vue.js approach for for this particular use-case, however I can see where the power of having full control over the JavaScript in a JSX implementation may be beneficial in other cases.

 

Those code snippets also show the differences in event handling of clicking on an item in the list. Again, the Vue.js approach "feels" cleaner and is easier to read in my opinion. The other major problem with the React solution is the necessity to create a "this" binding to these callback functions in the constructor for the component, i.e:

this.pageBack = this.pageBack.bind(this);
this.pageForward = this.pageForward.bind(this);
this.navigate = this.navigate.bind(this);
this.setRelativePath = this.setRelativePath.bind(this);

 

Other than these differences the end implementations were incredibly similar, although perhaps that is to be expected for such a simple use case. One thing that did immediately jump out was the necessity to do some post processing of node data in order to construct the breadcrumb trail and I plan to elaborate on that in my next post.

 

It might also be interesting to note that I created another NPM package to contain JavaScript code that can be shared between both implementations (and indeed implementations using other frameworks). I intend to keep adding to this as necessary with this research.

Outcomes