Angular vs. React (Part 2): component wrapping and delegation

Gara Mohamed
5 min readOct 29, 2018

--

Comparing React and Angular component wrapping capability.

“plate of vegetable salads” by Sara Dubler on Unsplash

Introduction

In the first article of this series, we talked about wrapping styles in components. In this second article, we continue our journey with the wrapping technique, but this time we talk about wrapping a component in an other one and establishing a delegation relationship between the two components. This will add more challenges.

The source code of the examples of the whole series is available here.

The full introduction to the series is here.

Let’s start by revisiting the advantages of wrapping, but this time for components.

Why we need component wrapping?

In a real application containing hundreds or thousands of components, it’s a best practice to:

  • Encapsulate the redundant code in reusable components.
  • Wrap third party components in custom components.

This will provide at least the following qualities:

  • Ensure coherence between different parts of the application.
  • Simplify development and avoid copy/past.
  • Reduce the bundle size by removing duplication and reducing code size.
  • Decouple the application from third party components and make it more easy to switch from one component to an other one.

Let’s jump to the case study.

Case study

Our case study is simple but illustrative. Our goal is to show the following content:

two bootstrap progress bars

We have two progress bars representing the progress level of two projects. The bars are bootstrap progress component and each one is preceded by a label describing the value.

So, let’s start with implementing the Angular version.

Angular implementation

In our first Angular version, we use the ng-bootstrap progress bar component directly in our code. The code showing the two progress bars is the following:

The first Angular version: direct use of the ngb-progressbar

The code is verbose, redundant and high coupled to the ng-bootstrap component. So, we will solve these problems by creating a component that wrap the the redundant html elements and delegate to the ngb-progressbar component.

The template of the refactored version is the following:

The second Angular version: use of our own component

The template is now less verbose and more simple to change. The application bundle will be smaller and the application style will be consistent. So, the result is so good, but let’s dive in the implementation details of the app-progress-bar component.

To make our app-progress-bar component as generic as the ngb-progressbar component and to expose all the latest potential to the former users, we should do two things:

  • First, we should copy all the inputs and outputs defined in ngb-progressbar component class into app-progress-bar component class. We should also take back any default value.
app-progress-bar with the copied inputs from ngb-progressbar
  • Then, in the template, we should delegate each input from app-progress-bar to ngb-progressbar, and emit each output from ngb-progressbar to app-progress-bar.
app-progress-bar delegating to ngb-progressbar

As we see, the delegation is too easy to do and can be automated for all the inputs except one. In the case of the max input, if we write [max]=”max”, the result will be the following:

The progress bars don’t show the colored bar

If the user of the app-progress-bar don’t define a value for the max input, we will pass undefined to the ngb-progressbar max input which will erase the default value and rise the bug. So, to resolve the problem, we should define a default max value.

In our case, we haven’t an output on the ng-bootstrap component, but if one day we will have a valueChange output:

  • First, we should declare an output in app-progress-bar component class:

@Output() valueChange = new EventEmitter<number>();

  • Second, in the template, we should emit the value like this

<ngb-progressbar (valueChange)=”valueChange.emit($event)” …>

Note: In this post, we only compare the delegation mechanisms that exist in both Angular and React. However, there are other types of delegation between components that exist only in Angular (e.g.: delegation between components associated to a FormControl). In this article, we ignore them as they are relatively complex and hey need an article in its own right.

Now, we will repeat the same thing but in a React application.

React implementation

Our journey with the React will be shorter than the Angular one. In the previous section we’ve detailed all the required steps to implement our wrapping component. So, in this section we will quickly show the equivalent code for each step with a brief description.

As with the first Angular version, to implement our case study, we start by using the reactstrap progress bar component directly in our code:

The first React version: direct use of the reactstrap Progress

In the refactored version, the div bloc of each progress bar will be replaced by an instance of our LabeledProgress new component:

The second React version: use of our own component

The LabeledProgress is a simple functional component wrapping the reactstrap Progress component:

LabeledProgress component

As shown above, to pass the props from the wrapper component to the wrapped component, we use two magic operators:

  • First, we use the rest operator to extract the props to delegate to the inner component.
  • Second, we use the spread operator to pass the extracted props to the inner component.

That’s all. We don’t have to worry about the default values because if the user of the outer component don’t specify a property value, we will not pass an undefined to the inner component. So, we will not accidentally override the default values.

The last thing to do, is to define the propTypes for our LabeledProgress component :

LabeledProgress propTypes

Using the spread operator, the Progress propTypes are reused in the definition of the LabeledProgress propTypes.

All rights. We can now make our conclusion by comparing the two results.

Conclusion

Wrapping components and establishing a delegation relationship between a wrapper/outer/parent and a wrapped/inner/child component can be done in both Angular and React. However, the implementation details vary between the two component engines.

Angular:

  • We should write a specific code but we can automate its generation using a dedicated tool.
  • We are forced to duplicate the inner component code into the outer component code.
  • We should be very careful with the default values passed to the wrapped component inputs.
  • When the wrapped component change its inputs and/or its outputs we should manually update the wrapper component.

React:

  • We use a generic code to wire the two components.
  • We don’t have to write a specific code to connect both of them.
  • As the views are written using the JSX, they are inherently dynamic.
  • When the wrapped component change its inputs and/or its outputs, the wrapper component isn’t impacted. Thereby, the component will be open to extension and closed to modification — The Open Closed SOLID Principle.

--

--