DEV Community

Mikko Vuorinen
Mikko Vuorinen

Posted on

Comparing React/Vue/Angular "Getting Started" experience - Building and Composing Components

This series compares my "getting started" experience and initial impressions of using React, Vue and Angular as a web developer already familiar with typescript and some frameworks. In this post I go through creating and composing components.


The series consists of the following posts:

Building and Composing Components

Most modern front-end web development can be described as component-oriented, but when it comes to implementation, the common ground is very small. Initiatives like web components have limited support in the most popular frameworks, and each framework has it's own flavour of components. In fact, it's probably one of the most important features to consider when deciding which framework to adopt.

Although components look very different in different frameworks, there is really no approach that is the best for all situations. Most of the time it's a matter of preference, but when deciding between frameworks, experience with multiple options is extremely valuable.

The application I'm building with each of the three frameworks is a wishlist services I named Listr. Visitors see a page that has a list of items, and they can reserve items or cancel their reservation. The idea is based on an existing service I have built and maintained. Links to the repositories are on each of the sections.

React

In React, a component is a function that returns a representation of the component's view. With a JSX extension to JavaScript, this representation can use a combination of HTML-like syntax and JavaScript expressions.

Using classes to define components in React is also possible. Because of my Aurelia background, I initially tried using the class syntax, but I soon realised that classes don't fit in well with React's approach. React limits the way objects and their state can be used, and classes don't behave the way I would expect them to. In my view it's better to use the function syntax.

React style for defining components as a function starts to feel natural fairly quickly. The structure itself is simple and straightforward, and coding is very slick thanks to great support provided by VS Code. There are several times when I need to google how TypeScript fits into the picture.

Creating component hierarchies is definitely one of the strong points in React, especially when using JSX syntax. Before trying it myself, I was quite sceptical about writing HTML in JavaScript, but with the right tooling, it's far from the string concatenation and escape character mess that I thought it might be.

Child components are defined as HTML-like elements in the return value of the component function. Below is an example of an Item-component that shows the item label, number of reservations, and two child components that represent buttons:

export const Item: FunctionComponent<ItemProps> = (props) => (
    <div className="listr-item">
        <span className="listr-item-name">{props.item.label}</span>
        <span className="listr-item-count">({props.item.reservedCount}/{props.item.count})</span>
        <ReserveButton />
        <CancelButton />
    </div>
)

Creating more complex structures within the component view is very easy because it can be done by using JavaScript:

return (
    <div className="listr-list">
        <h1>{props.name}</h1>
        {list?.items.map((item, index) => (
            <Item
                key={index}
                item={item} />
        ))}
    </div>
);

In short, creating components is where React is at its best. At this point, I'm starting to like writing React quite a bit, and looking forward to learn more!

Source code: Listr components in React

Vue.js

Vue.js components are a step closer to the MVVM style that I'm more familiar with. Although components can be written in one file, there is a separate view template and a script part (let's call it "view model").

The template syntax is fairly easy to follow, but documentation is needed to know how to handle ifs and loops and the like. Some of the small details are not intuitively clear, for example the restriction that {{}} cannot be used inside HTML attributes.

<template>
  <div class="listr-list">
    <h1>{{ name }}</h1>
    <div v-if="!!list">
      <Item
        v-for="(item, index) in list.items"
        v-bind:key="index"
        v-bind:item="item"
        />
    </div>
  </div>
</template>

The most confusing part with Vue components when starting to build the first view model is that there are several different styles to pick from. The Vue CLI generated the template using the class syntax and @Component decorator, but the documentation only shows the following syntax:

Vue.component('my-component', {
  // ...
}

This makes following the documentation sometimes a bit difficult, especially when TypeScript comes into the picture as well.

There is also significantly more boilerplate code required for defining comonents in Vue. For example, all child components need to be defined in the parent component definition in the components property of the decorator. Defining component properties requires a default value in the @Prop decorator to work, as the standard property default value will not work as expected.

@Component({
  components: {
    Item
  }
})
export default class List extends Vue {
  @Prop({ default: '' })
  name!: string
}

Source code: Listr components in Vue.js

Angular

Angular is still very loyal to its MVVM roots. Roughly speaking, the HTML template of a component represents the view, and the TypeScript part is the viewmodel. There is a lot of boilerplate code required to create a component, but well defined conventions and the CLI generators built around them mean that a lot of that can be automatically generated.

@Component({
  selector: 'app-item',
  templateUrl: './item.component.html'
})
export class ItemComponent {
  @Input() item!: ItemData;
}

Angular components are defined as TypeScript classes, and follow the object-oriented programming style much more closely than React or Vue. There are some additional JS decorators that are needed to give classes and properties specific meaning, but it's quite straightforward to design an Angular application using classes and object. Even inheritance can be used, to some extent. This seems to me one of the most prominent differences between Angular and the other two frameworks, and I think it should play a key role when making the decision. Angular seems to be in this sense much closer to Aurelia.

<div class="listr-list">
  <h1>{{ name }}</h1>
  <div *ngIf="!!list">
    <app-item
      *ngFor="let item of list.items"
      [item]="item"
      (reserve)="handleReserve($event)"
      (cancel)="handleCancel($event)"></app-item>
  </div>
</div>

Using components and composing structures in Angular templates is quite easy, but one of my main complaints about Angular is the template syntax. There are several different ways of adding bindings or logic into the template, and they all seem to use different syntax. A very simple example already uses {{data}} for displaying data and *attr, (attr) and [attr] in the element attribute names. In my opinion, this makes the HTML template look messy and difficult to see the underlying structure.

On the other hand, the code in viewmodels is quite easy to follow without extensive experience using Angular. Being natively TypeScript is a big plus in my books, and core interfaces can be used to help with ensuring correct usage of the framework. The code is more verbose, especially when comparing to React, but it seems to be easier to separate the framework-dependent parts from the application logic.

Conclusion

Components are used in a similar way in React, Vue.js and Angular, but each have their own take on how the component view and logic is defined. A simplified way of putting it is to say that React is more functional, Angular is more object oriented, and Vue is in between. The reality is much more complex than that, but based on my initial experience with the three, I think it's not completely untrue.


Thank you for reading! If you have any feedback or questions, please leave a comment below. I would love to hear others' experiences on the subject.

Top comments (0)