React for Angular Developer (part 2)

Sy Truong
4 min readJun 8, 2021

--

Continuing from the previous article, today we continue to look at how to solve the problem of Component, Data binding, … in React and Angular.

Component

React components are similar to Angular directives, they are used to abstract complex DOM structures and break them down behaviorally for reuse. For example, to do a slide show with Angular.

// index.html
<div ng-controller="SlideShowController">
<slide-show slides="slides">
</slide-show>
</div>
// slide-show.html
<div class="slideshow">
<ul class="slideshow-slides">
<li ng-repeat="slide in slides" ng-class="{ active: $index == activeIndex }">
<figure>
<img ng-src="{{ slide.imageUrl }}" />
<figcaption ng-show="slide.caption">{{ slide.caption }}</figcaption>
</figure>
</li>
</ul>
<ul class="slideshow-dots">
<li ng-repeat="slide in slides" ng-class="{ active: $index == activeIndex }">
<a ng-click="jumpToSlide($index)">{{ $index + 1 }}</a>
</li>
</ul>
</div>
// js
app.controller("SlideShowController", function($scope) {
$scope.slides = [{
imageUrl: "image.jpg",
caption: "This is image" },{
imageUrl: "image.jpg",
caption: "This is image" }];
});
app.directive("slideShow", function() {
return {
restrict: 'E',
scope: {
slides: '='
},
template: 'slide-show.html',
link: function($scope, element, attrs) {
$scope.activeIndex = 0;
$scope.jumpToSlide = function(index) {
$scope.activeIndex = index;
};
}
};
});

Whereas with React, the component will be rendered inside another component, exchanging data with each other via props.

let _slides = [{
imageUrl: "image.jpg",
caption: "This is image"
}, {
imageUrl: "image.jpg",
caption: "This is image"
}];
class App extends React.Component {
render() {
return <SlideShow slides={ _slides } />
}}
class SlideShow extends React.Component {
constructor() {
super()
this.state = { activeIndex: 0 };
}
jumpToSlide(index) {
this.setState({ activeIndex: index });
}
render() {
return (
<div className="slideshow">
<ul className="slideshow-slides">
{
this.props.slides.map((slide, index) => (
<li className={ classNames({ active: index == this.state.activeIndex }) }>
<figure>
<img src={ slide.imageUrl } />
{ slide.caption ? <figcaption>{ slide.caption }</figcaption> : null }
</figure>
</li>
))
}
</ul>
<ul className="slideshow-dots">
{
this.props.slides.map((slide, index) => (
<li className={ (index == this.state.activeIndex) ? 'active': '' }>
<a onClick={ (event)=> this.jumpToSlide(index) }>{ index + 1 }</a>
</li>
))
}
</ul>
</div>
);
}
}

React component contains state within it (this.state), which you can modify by calling this.setState({ key: value}). Any change to the component’s state causes it to re-render itself.

Events in React look like old-school styles, like inline event handler like onClick or similar. But don’t think like it’s boring, because React is actually trying to gain performance from these points, which creates high performance delegated event listeners.

Two-Way Binding

Angular uses ng-model and $scope to create a link between the data flows that are exchanged between the form element and the properties of the Javascript object inside the controller.

// Javascript
app.controller("TwoWayController", function($scope) {
$scope.person = {
name: 'Sy Truong'
};
});
// HTML
<div ng-controller="TwoWayController">
<input ng-model="person.name" />
<p>Hello {{ person.name }}!</p>
</div>

React does not use this model, it uses one-way data flow instead.

class OneWayComponent extends React.Component {
constructor() {
super()
this.state = { name: 'Sy Truong'}
}
change(event) {
this.setState({ name: event.target.value });
} render() {
return (
<div>
<input value={ this.state.name } onChange={ (event)=> this.change(event) } />
<p>Hello { this.state.name }!</p>
</div>
);
}
}

The <input> tag in the above code is called controlled input, which means that whenever the value of the controlled input is changed, the render function will be called. The component itself is called stateful because it manages its own data. This is not recommended for most components, so the idea is to keep the component, we will exchange data via props.

Usually, a stateful container component or controller view is usually at the top of the DOM tree with a bunch of stateless child components underneath, to have a better understanding of why components should have a state here https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html#what-components-should-have-state.

Flexibility

With one-way down data flow, data has only one direction so it is easier for us to call the parent component’s methods via callback. This flexibility gives developers the ability to control a lot of things when refactoring components to make the components visible simply. If the refactored component does not contain any state, then we can convert it to a pure function. It sounds confusing, but you can imagine it through the following code.

const OneWayComponent = (props)=> (
<div>
<input value={ props.name } onChange={ (event)=> props.onChange(event.target.value) } />
<p>Hello { props.name }!</p>
</div>
);
class ParentComponent extends React.Component {
constructor() {
super()
this.state = { name: 'Sy Truong' };
} change(value) {
this.setState({name: value});
}
render() {
return (
<div>
<OneWayComponent name={ this.state.name } onChange={ this.change.bind(this) } />
<p>Hello { this.state.name }!</p>
</div>
)
}
}

This can seem quite annoying for those who are used to using two-way data binding. The benefit of having many small components in the rendering layer, which only accepts data as props and renders them as the default action, and hence since components are so simple to have can reduce the number of bugs, less code = less bug. This also prevents UI instability, which often happens when data is placed and maintained in different places.

Dependency Injection, Services, Filters

Today, dependency management in Javascript is more convenient than ever thanks to Webpack or Browserify. Below is a comparison of dependency usage in Angular and React, with ES6 statements becoming much closer to class-based languages.

// An Angular directive with dependencies
app.directive('myComponent', ['Notifier', '$filter', function(Notifier, $filter) {
const formatName = $filter('formatName');
// use Notifier / formatName}]// ES6 Modules used by a React component
import Notifier from "services/notifier";
import { formatName } from "filters";
class MyComponent extends React.Component {
// use Notifier / formatName }

Conclusion

In short, if you’re having issues with rendering performance, a common problem when using Angular in your application, you can boost performance by switching rendering to React. It’s also not too complicated to use multiple libraries to solve the same problem in an application.

While React and Angular solve some of the same problems, the solutions are completely different. React favors the function declaration method when the components are pure functions which help to avoid errors.

Through this article, hopefully, you have had a basic look at how to solve React and Angular problems, and can help you switch context more easily.

Goodbye and see you in the next posts.

--

--