Featured

My upcoming conferences and workshops

In May-June 2018 I’ll be participating in the following events:

1. O’Reilly Fluent conference in San Jose
2. BuzzJS in New York
3. First steps in Angular, online workshop for O’Reilly

Advertisements

How I migrated a dozen of projects to Angular 6

In this article, I’ll share with you my experience of upgrading more than a dozen of Anguar 5 projects to Angular 6. These projects were small to medium in size, but they used lots of various Angular features because these are the projects from the second edition of our Angular book. Many of these projects had multiple apps configured in the file .angular-cli.json, and they were automatically migrated into the new project structure as defined in the new configuration file angular.json.

First of all, there’s the site https://update.angular.io that gives you an idea of how to do the upgrade from version X to version Y, and you certainly need to read the instructions there first. But the devil is in the detail, right?

Theoretically, the upgrade should be a 1-2-3 process that consists of the following three steps:

1. npm install @angular/cli@latest –save-dev
Run this command in your project’s dir, to upgrade (and install) the latest Angular CLI version in the devDependencies section of package.json. This command shouldn’t need @latest, but it does.

2. ng update @angular/cli
Run this command to convert the project configuration file .angular-cli.json into angular.json introduced by Angular 6.It also will update testing and tslint config files.

3. ng update @angular/core
Run this command to upgrade all Angular dependencies in the package.json file (except Angular Material and Angular Flex Layout, if used).

What else is needed

On my computer, I had Angular CLI 6 install globally, and my typical project had the line “typescript”: “~2.4.2” in devDependency section of package.json.

Before running and upgrade steps, bump up the TypeScript compiler version in your project or you’ll get an error “@angular/compiler-cli” has an incompatible peer dependency to “typescript” during the step 3. Start any project upgrade with manually changing this dependency to “typescript”: “~2.7.2”. If you still see that error, delete the node_module directory and re-run step 3.

If you use the Angular Material library, run ng update @angular/material to update its dependencies in package.json.

If you use the Flex Layout library, modify its version to 6.0.0-beta15 or later prior to running ng update @angular/core.

Your project’s .angular-cli.json might include the file favicon.ico in the asset’s property that’s not used in your app. Angular 5 would still launch your app even if this file was missing. In Angular 6, you need to explicitly remove all occurrences of favicon.ico in the newly generated angular.json.

After migration, I noticed some strange behavior in the UI rendering, which seems like a bug. In some of my apps, I had the following HTML in the component templates:

<a [routerLink]="['/']">Home</a> 
<a [routerLink]="['/product']">Product</a> 

In Angular 5, it rendered just fine, but after migration to Angular 6, the browser rendered both links without the space between them: HomeProduct. Adding &nbsp; after the first anchor tag helped. I thought it might be related to the Angular compiler’s option preserveWhitespaces, but it didn’t.

Starting from TypeScript 2.7, you may need to take care of the error TS2564: Property ‘SoAndSo’ has no initializer and is not definitely assigned in the constructor. For example, the following class variable declaration won’t compile:

product: Product[];

Either set the TypeScript compiler’s option strictPropertyInitialization to false or explicitly initialize class variables, e.g.

product: Product[] = [];

Upgrading your app to RxJS 6

During the upgrade, I spent the most time updating the code related to breaking changes in RxJS 6.

Your updated package.json will include the dependency “rxjs-compat”: “^6.0.0-rc.0” after step 3. At the time of this writing, the current version of rxjs-compat is 6.1.0, so if you decide to keep rxjs-compat, update its version in package.json and reinstall dependencies. Theoretically, having the rxjs-compat package should allow you to run your app without making any changes in the app code that uses RxJS API. In practice, this may not be the case and the app may fail either during the build- or runtime.

So I decided to remove the rxjs-compat dependency and modify my code to conform to RxJS 6 structure. Remove rxjs-compat from your package.json file to avoid unnecessary increase of your app bundle size. Then run ng serve and fix the RxJS errors (if any) one by one. Then load your app in the browser and keep the browser console wide open so you won’t miss the RxJS-related runtime errors, if any.

The internal structure of RxJS 6 has changed, and you need to change the import statements to get the classes and operators from the proper places. You may start with reading this upgrade guide. Disclaimer: I didn’t follow my own advice and started learning by doing.

In the past, the golden rule was “Don’t import Observable from rxjs, import it from rxjs/observable otherwise the entire RxJS library will be included in your app bundle”. No more. The new golden rule is import { Observable } from “rxjs”; The same applies to Subject, Subscription, interval(), of(), and many other RxJS thingies.

You need to stop using the dot-chainable operators (they simply won’t work without rxjs-compat package). Now you have to use the RxJS pipeable operators, and your imports should look like this:
import { debounceTime, map } from ‘rxjs/operators’;

The ng update command added the rxjs-compat package to your project, and if you’re lucky, your app might run as before without changing the code. But some of my apps gave me build errors, while others crashed at runtime.

For example, in one of my apps, I had this:

import { Observable } from "rxjs";
...
const myObservable$ = Observable.fromEvent(...)

Got the TypeScript error “error TS2339: Property ‘fromEvent’ does not exist on type ‘typeof Observable’.” Here’s the fix:

import { fromEvent } from "rxjs";
...
const myObservable$ = fromEvent(...)

In another app, I had this:

import {Observable} from 'rxjs';
...
return Observable.empty();

It also gave me the error TS2339. This time the fix included replacing the deprecated function empty() with the constant EMPTY:

import {EMPTY} from 'rxjs';
...
return EMPTY;

Another app had this:

numbers$ = Observable.interval(1000)...

This code sneaked through the build phase, but crashed my app during runtime. Here’s the fix:

import {interval} from "rxjs";
numbers$ = interval(1000)...

Don’t bet too heavily on rxjs-compat. This package may help you to quickly get your app running in Angular 6, but until you remove rxjs-compat from your project, don’t report to your boss that migration is done. Find the time and fix the code in your Angular 5 app to conform to RxJS 6. After this is done, migrate your app to Angular 6.

The next one is for those two people who also use RxJS WebSocketSubject. The API has changed in RxJS 6. In the past, you’d do this:

import { WebSocketSubject } from 'rxjs/observable/dom/WebSocketSubject';
...
let myWebSocket = WebSocketSubject.create(wsUrl);
...
myWebSocket.next(JSON.stringify(objectToSend));

To make it work in RxJS 6, I’ve changed it to the following:

import { WebSocketSubject } from 'rxjs/websocket';
...
let myWebSocket = new WebSocketSubject(wsUrl);
...
myWebSocket.next(objectToSend);

And one more thing. If you use Angular Material library, you may run into some breaking changes in the UI components. But overall, conversion of a project to Angular 6 is not a time-consuming process.

P.S. If you use NGRX, don’t forget to upgrade all ngrx packages to version 6 (at the time of this writing, it’s 6.0.0-beta.3).

Starting a new book on TypeScript

It’s Saturday morning and it’s raining in New York City. There is not much you can do. Why not start writing a new book? The agreement with the publisher is signed, and my colleague Anton Moiseev kindly agreed to be my co-author again. The book will have a title Get Programming with TypeScript, and its first chapters have to be released in August.

In this blog, I’ll show you the first two pages that I just wrote as well as a table of contents (subject to change). Besides introducing the code samples illustrating the syntax of the language, we’ll be developing a blockchain app using TypeScript in different environments: in Node.js, in the browser without frameworks, with Angular, with React… Meanwhile, the first two pages are ready.

Unit 1. Getting started with TypeScript

This unit starts with presenting the benefits of programming in TypeScript over JavaScript. Then we’ll install the TypeScript compiler and the IDE, and you’ll learn about the process of transforming a TypeScript program into its JavaScript equivalent that can be run in any JavaScript engine. After that, you’ll see how various TypeScript types can be used in a program. In the hands-on section, we’ll introduce you to the blockchain project and will develop a library that will be used in subsequent units.

We’d like to make a clear distinction between the syntax introduced in ECMAScript specification, and the syntax that’s unique to TypeScript. That’s why we recommend you to read the Appendix A first, so you know where ECMAScript ends and TypeScript begins.

Why program in TypeScript

TypeScript is a compile-to-JavaScript language. It’s also a superset JavaScript, which means that you can take any JavaScript file, e.g. myProgram.js, change its name extension from .js to .ts, and the file myProgram.ts becomes a valid TypeScript program without changing a single line of code.

The word superset means that it contains something additional compared to the set. The main addition to the JavaScript is static types. You can declare a variable of a certain type, and any attempt to assign a value of a different type to it results in a compilation error. This is not the case in JavaScript, where you can change the type of a variable anytime you want during runtime.

But web browsers don’t support TypeScript and this won’t change in the foreseeable future. The program written in TypeScript has to be transpiled into JavaScript first, and then it can be executed in the browser or a standalone JavaScript engine.

The difference between transpiling and compiling is that the latter turns the source code of a program into a bytecode or machine code, whereas the former converts the program from one language to another, e.g. from TypeScript to JavaScript.

Then why go through a hassle of writing a program in TypeScript and then transpiling it into JavaScript, if you could write this program in JavaScript in the first place?

In essence, TypeScript is JavaScript with static types. For example, if you declare a variable as a string, trying to assign a numeric value to it will result in the compile-time error.

let customerId: string
customerId = 123;  // compile-time error

In JavaSript, you can’t explicitly assign the type to a variable, and you could write

let customerId = "A15BN";
customerId = 123;  // no errors 

Let’s write a JavaScript function that applies the provided discount to a price. It has two arguments and both must be numbers.

function getFinalPrice(price, discount) {
  return price - price/discount;
}

How do you know that the arguments must be numbers? First of all, you wrote this function and having an exceptional memory, you may just remember all types of all functions arguments. Secondly, you use descriptive names of the arguments that hint their types. Thirdly, you could guess the types by reading the function code.

This is a pretty simple function, which is not always the case. But let’s say someone (not you) would invoke this function by providing a discount as a string, this function would print NaN during the runtime.

console.log(getFinalPrice( 100, 10));    // prints 90
console.log(getFinalPrice( 100, "10%")); // prints NaN

In TypeScript, you could provide the types for the function arguments, so if someone would try to invoke the function with a wrong type of an argument, this error would be caught as you were typing. Let’s see it in action.

The official TypeScript web page is located here. It offers the language documentation and a playground, where you could enter the code snippets in TypeScript, which would be immediately transpiled into JavaScript.

Follow this link https://bit.ly/2IyVNlj, and you’ll see our code snippet in the TypeScript playground, with the squiggly red line under “10%”. If you hover the mouse over the erroneous code, you’ll see a prompt explaining the error as shown below.

This error was caught by the TypeScript static code analyzer as I was typing. Moreover, if you specify the variable types, your IDE would offer the auto-complete feature suggesting you the argument names and types of the getFinalPrice() function.

Isn’t it nice that the errors are caught during the compile time? I think so. The vast majority of the developers with the background in such languages as Java, C++, C# and others take it for granted that the errors are caught during compile time, and they welcome TypeScript.

Having said that, I need to admit that some of the hard-core JavaScript developers say that TypeScript slows them down by requiring to use types, and in JavaScript, they’d be more productive. But the majority of the web developers are not JavaScript ninjas and can appreciate a helping hand offered by TypeScript.

This is all I got so far.

Below is the current version of the Table of Contents.

Unit 1: Getting started with TypeScript
1.1 Why developing in TypeScript
1.2 Installing and using the TypeScript compiler
1.3 Introducing the Visual Studio Code IDE
1.4 Getting familiar with TypeScript syntax
1.4.1 Type annotations and inferred types
1.5. Hands-on: Starting the blockchain project
1.5.1 Introducing the blockchain project
1.5.2 Developing a library that implements a mining algorithm

Unit 2 Classes and interfaces
2.1 Classes
2.1.1 Instance and static methods
2.1.2 Properties and access modifiers public, private, protected
2.1.3 Constructors
2.1.4 Abstract classes
2.2 Interfaces
2.2.1 Declaring custom types with interfaces
2.2.2 Interface as a contract
2.2.3 Declaring types with classes vs interfaces
2.3 Hands-on: Developing browser-based blockchain node with TypeScript
2.3.1 Working with DOM elements
2.3.2 Making AJAX requests
2.3.3 Implementing the blockchain node for

Unit 3 Generics
3.1 Intro to Generics
3.2 Creating custom generics
3.3 Hands-on: Developing Angular client for the browser-based blockchain node
3.3.1 Brief overview of Angular
3.3.2 Creating a new app with Angular CLI
3.3.3 Generating Angular components and services
3.3.4 Implementing the blockchain node in Angular

Unit 4 Tooling
4.1 Improving code quality with TSLint
4.2 Bundling the TypeScript code with Webpack
4.4 Debugging TypeScript in the browser
4.5 Unit testing TypeScript code
4.7 Hands-on: Developing React client for the browser-based blockchain node
4.7.1 Brief overview of React
4.7.2 Transpiling TypeScript with Babel
4.7.3 Creating a React app for the blockchain node

Unit 5 Advanced types
5.1 Unions, intersections, and the type keyword
5.2 Enums
5.3 Mapped types
5.4 Conditional types
5.5. Hands-on: Developing a server for discovering blockchain nodes in the network

Unit 6 Advanced TypeScript features
6.1 Decorators
6.1.1 Creating custom decorators
6.2 Mixins
6.3 Dynamic imports
6.4 Hands-on: Implementing peer-to-peer blockchain nodes communication
6.4.1 Introducing WebRTC
6.4.2 Implementing nodes communication via WebRTC

Appendix A Modern JavaScript
A.1 The keywords let and const
A.2 Functions
A.2.1 Default and optional function parameters
A.2.2 Fat arrow function expressions
A.3 Classes and inheritance
A.4. Asynchronous programming
A.4.1 From callbacks to promises
A.4.2 async and await
A.5 Destructuring
A.6 The Spread operator
A.6.1 Cloning objects with the Spread operator
A.7 The Rest operator
A.8 Iterating data collections

Appendix B Using TypeScript with JavaScript libraries
B.1 Type declaration files
B.1.1 How to create type declaration files
B.2 Using the JavaScript lodash library in TypeScript code

RxJS Essentials: Part 9: Dealing with breaking changes in RxJS 6

This article is a part of my RxJS series, and the previous post is here.

My plan for this morning was to spend 15 min skimming through my RxJS slides and code samples for the upcoming presentation. I did this presentation multiple times, and my code samples published on CodePen just worked. No more.

RxJS 6 was recently released, and my code samples stopped working. I’m not sure if these particular issues were listed somewhere as breaking changes, but I’d like to share my findings with you. I’ve been using the following CDN to get RxJS 6: https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.0.0/rxjs.umd.js.

In the past, you could use the Rx object as in Rx.Observable. No more.

rxjs is the new Rx

For example, my code sample that had Rx.Observable.create() is broken in RxJS 6 complaining that Rx is not defined. The broken code is here.

Say you need to get a hold of the Observable object in RxJS 6. I did it using the JavaScript destructuring syntax:

const { Observable } = rxjs;

Now you can just write Observable.create(). This fixed my broken code sample for Observable.create(), and the working version is here.

The next broken code sample was related to operators. I remember reading that dot-chainable operators shouldn’t be used in RxJS 6. Using pipeable operators is the way to go.

For backward compatibility of your app, you need to add the package rxjs-compat to be able to use dot-chainable operators. After replacing all dot-chainable with pipeable operators, uninstall rxjs-compat.

Here’s the broken code sample that uses dot-chainable operators map and filter.

To fix this code, I used the destructuring syntax again to get the pipeable version of the map and filter operators like this:

const { filter, map } = rxjs.operators;

Basically, I replaced this:

Rx.Observable.from(beers)  
    .filter(beer => beer.price < 8) 
    .map(beer => beer.name + ": $" + beer.price) 
    .subscribe()

with this:

const { from } = rxjs; 
const { filter, map } = rxjs.operators;

from(beers).pipe(
    filter(beer => beer.price < 8), 
    map(beer => beer.name + ": $" + beer.price) 
    )
    .subscribe()

The working version of the code sample that uses pipeable operators map and filter is here.

Disclaimer. These were quick fixes that I came up with. I wouldn’t be surprised if there was a different way to accomplished the same results. If you find one, please let me know. Gotta share, right?

And one more thing. Importing observables like this is not cool anymore:

import {Observable} from "rxjs/observable";

You need to do it like this:

import {Observable} from "rxjs";

For detailed coverage of how to migrate RxJS-related code see this doc.

Angular: When using ngrx is an overkill

State management is one of the most important aspects of any app that has UI. redux is a popular library for maintaining state in the React community. ngrx is a redux-inspired library for maintaining state in Angular apps. But if redux is a rather simple library, ngrx is not so much, and its workflow is illustrated in the diagram below.

In this blog, I’m not going to explain how ngrx works in detail. You can learn it by going through one of the online tutorials, attending our online workshop, or reading the last chapter of our Angular book. I’ll just show you a video comparing two small apps that have the same functionality, but one of them implements state management by using RxJS BehaviorSubject in an Angular service, while the other uses ngrx.

The app that doesn’t use ngrx has about 80 lines of code and its production build size is 268KB. The ngrx version of this app has about 160 lines of code and its production build weighs 315KB.

In short, I do not recommend using ngrx for state management of small and mid-size apps.

Typically, you use a library to write less code, but the current version of ngrx requires you to write more code.

RxJS Essentials: Part 8: Pipeable operators

In this article, we’ll discuss pipeable operators introduced in RxJS 5.5. The previous articles in this series include:

1. Basic Terms
2. Operators map, filter, and reduce
3. Using Observable.create()
4. Using RxJS Subject
5. The flatMap operator
6. The switchMap operator
7. Handling errors with the catch operator

Pipeable operators are those that can be chained using the pipe() function, whereas dot-chaining operators are chained with the dot as shown in this blog. Let’s discuss the dot-chaining operators first to understand why the pipeable operators were introduced in RxJS.

If you have RxJS installed, the dot-chaining operators can be imported from the directory rxjs/add/operator, for example:

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/filter';

These operators patch the code of the Observable.prototype and become a part of this object. If later on, you decide to remove say filter operator from the code that handles the observable stream but will forget to remove the corresponding import statement, the code that implements filter remains a part of the Observable.prototype. When the bundlers will try to eliminate the unused code (a.k.a. tree shaking), they may decide to keep the code of the filter operator in the Observable even though it’s not being used in the app.

RxJS 5.5 introduced pipeable operators that are pure functions and do not patch the Observable. You can import operators using the ES6 import syntax (e.g. import {map} from ‘rxjs/operators’) and then wrap them into a function pipe() that takes a variable number of parameters, i.e. chainable operators.

The subscriber in the next code snippet will receive the same data as the ones from the first code sample in this blog, but it’s a better version from the tree-shaking perspective because it uses pipeable operators. The next code sample includes the import statement assuming that RxJS is locally installed.

import {map, filter} from 'rxjs/operators'; // 1
...
Rx.Observable.from(beers)
    .pipe(  // 2
         filter(beer => beer.price < 8) ,
         map(beer => ${beer.name}: $${beer.price})
      ) 
    .subscribe( 
        beer => console.log(beer),
        err => console.error(err),
        () => console.log("Streaming is over")
);

1.Importing pipeable operators from rxjs/operators instead of rxjs/add/operator
2. Wrapping pipeable operators into the function pipe()

Now if you’ll remove the line filter from the above code snippet, the tree-shaking module of the bundlers (e.g. Webpack 4) can recognize that the imported function is not used and the code of the filter operator won’t be included in the bundles.

To see it in action in CodePen, follow this link.

NOTE: Since the pipeable operators are standalone functions, to avoid conflicts with the JavaScript catch statement the pipeable version of the catch operator is called catchError.

Debugging observables

The operator do and its pipeable equivalent tap performs a side effect (e.g. log some data) for every value emitted by the source observable, but returns an observable that is identical to the source. In particular, these operators can be used for debugging purposes.

Say, you have a chain of operators and want to see the observable values before and after a certain operator is applied. The tap operator will allow you to log the values:

import { map, tap } from 'rxjs/operators';

myObservable$
  .pipe(
    tap(beer => console.log(`Before: ${beer}`)),
    map(beer => `${beer.name}, ${beer.country}`),
    tap(beer => console.log(`After: ${beer}`))
  )
  .subscribe(...);

In this example, we print the emitted value before and after the map operator is applied. The tap operator doesn’t change the observable data – it just passes it through to the next operator or the method subscribe().

Refactor your code to use exclusively pipeable operators, because starting from RxJS 6, the dot-chaining operators will be supported only if you install a compatibility package.

What’s coming in Angular 6+

The release of Angular 6 is around the corner, and in this blog, I’d like to highlight some of its new features announced by the Angular Team.

I started working with Angular when it was in its early alpha versions. Every new Alpha, Beta, and Release Candidate was full of breaking changes, and the announcement of each new release was giving me goosebumps.

After the official release of Angular 2 in September of 2016, the Angular Team started to care about us the developers from the trenches; new major releases come twice a year and switching from one release to another is an easy task. Angular is gaining popularity in the enterprise world leaps and bounds, and the Angular team continues improving this framework. To the best of my knowledge, these are the new and upcoming features:

Angular Elements. While Angular is a great choice for developing Single-Page Applications, creating a widget that can be added to any existing web page was not a simple task. The package called Angular Elements will allow you to create an Angular component and publish it as a Web Component, which can be used in any HTML page. Say there is an existing non-SPA app built using JavaScript and jQuery. The developers of this app will be able to use Web Components built in Angular in the pages of such an app. In our opinion, this killer feature will open many enterprise doors to the Angular framework.

Ivy renderer. This is a code name of a new renderer that will make the size of the app smaller and the compilation faster. The size of the Hello World app is only 3KB gzipped. The Angular Team promises that switching to Ivy rendered will be smooth, and I’ll take my hat off if they’ll be able to make it a non-breaking change.

Bazel and Closure Compiler. Bazel is a build system used for nearly all software built at Google, including their 300+ apps written in Angular. Closure Compiler is the bundling optimizer used to create JavaScript artifacts for nearly all Google web applications. The Closure Compiler consistently generates smaller bundles and does a better job in dead code elimination compared to Webpack and Rollup bundlers. In the upcoming releases of the Angular framework, you’ll be able to use this toolchain for building your apps as well.

Component Dev Kit (CDK). This package is already used by the Angular Material library, which offers 30+ UI components. What if you don’t want to use Angular Material but want to build your own library of UI components and control page layouts? CDK allows you to do this. It also supports Responsive Web Design layouts eliminating the need for using libraries like Flex Layout or learning CSS Grid. CDK was released in December of 2017, but the Angular Team keeps improving it.

Schematics and ng update. Angular CLI generates Angular artifacts using the technology called Schematics. If you decide to create your own templates and have Angular CLI use it, Schematics will help you with this. Staring from Angular CLI 1.7, you can use the ng update that automatically updates your project dependencies and makes automated version fixes. With Schematics, you’ll be able to create your own code transformations like ng update.

I’ looking forward to these features that will make Angular even better, but what else could be improved, that’s not on the roadmap yet? Angular CLI is a great tool, but it has lots and lots of dependencies on the third-party software. Over the last year, several times I’ve experienced broken builds in the latest releases of Angular CLI that were caused by some erroneous release of a third-party package.

The Angular CLI folks are pretty good at releasing patches when errors are reported, but the process of regression testing should be improved, so these errors wouldn’t even sneak in. I stopped using the ^ sign for the version of @angular/clip in package.json. I use the exact version that works for me unless I have a compelling reason for upgrade.

Go Angular!

From a convenience store to Redux architecture

Imagine that you’re a proud owner of a convenience store that sells various products. Remember how did you start? You rented an empty place (i.e. the store was in its initial state). Then you purchased shelves and ordered products. After that, multiple vendors started delivering products. You hired employees that arranged these products on the shelves in a certain order changing the state of the store. Then you put out the Grand Opening sign and lots of colorful balloons.

Customers started visiting your store and buy products. When the store is open, some products lay on the shelves, and some products are in the shopping carts of customers. Some customers are waiting in lines at the cash registers, and there are store employees there. In other words, we can say that at any given moment, your store has the current state.

If a customer takes an action, e.g. buys (or returns) five bottles of water, the cashier scans the barcode, and this reduces (or increases) the number of bottles in the inventory, i.e. updates the state. If a vendor delivers new products, your clerk updates the inventory (i.e. state) accordingly.

Your web app can also maintain a store that holds the state of your app. Similarly to a real store, at any given time your app’s store has a current state. Some data collections have specific data retrieved from the server and, possibly modified by the user. Some radio buttons are checked, the user selected some products and navigated to some routes represented by a specific URL.

If the user interacts with the UI, or the server sends new data, these actions should ask the store object to update the state. But to keep track of the state changes, the current state object is never updated, but a new instance of the state object is created.

What’s Redux?

Redux an open-source JavaScript library that takes care of managing application state. Initially, the React.js developers made Redux popular, but since it’s just a library for maintaining an app state, it can be used in any JavaScript app. Redux is based on the following three principles:

  • Single source of truth. There is a single store where your app contains the state that can be represented by an object tree.
  • State is read-only. When an action is emitted, the reducer function won’t update, but clone the current state and update it based on the action.
  • State changes are made with pure functions. You write the reducer function(s) that takes an action and the current state object, and returns a new state.

In Redux, the data flow is unidirectional:

1. The app component dispatches the action on the store
2. The reducer (a pure function) takes the current state object and then clones, updates, and returns it.
3. The app component subscribes to the store, receives the new state object and updates the UI accordingly.

This is how the Redux unidirectional data flow can be presented if used in a web app.

An action is a JavaScript object that has a property `type` describing what happened in your app, e.g. the user wants to buy the IBM stock. Besides the property type, and action object can optionally have another property with the payload of data that should somehow change the app state, for example:

{
  type: 'BUY_STOCK',
  stock: { symbol: 'IBM', quantity: 100} 
}

This object only describes the action and provides the payload, but it doesn’t know how the state should be changed. Who does? The reducer.

A reducer is a pure function that specifies how the state should be changed. The reducer never changes the current state but creates a new (and updated) version of it. In other words, the state object is immutable. The reducer creates a copy of the state object and returns a new reference to it. If you use the Angular framework, it’s a binding change event, and all interested parties will immediately know that the state has changed without requiring expensive value checking in the entire state tree.

A reducer function has the following signature:

function (previousState, action): State {...} 

Should the reducer function implement the app functionality like placing an order, which requires work with external services? Of course not, because reducers are meant for updating and returning the app state, e.g. the stock to buy is “IBM”. Besides, implementing the app logic would require interaction with the environment external to the reducer, i.e. it would cause side effects, and pure functions can’t have side effects.

The reducer can implement minimal app logic related to the state change. For example, the user decides to cancel the order, which requires a reset of certain fields on the state object. The main app logic remains in your application code (e.g. in services) unless a concrete implementation of the Redux-inspired library offers a special place meant for the code with side effects.

Why storing an app state in a single place is important

Recently, I was working on a project for a car manufacturer. This was a web app that allowed a prospective buyer to configure a car by selecting from tons of packages and options (e.g. model, interior and exterior colors, length of the chassis et al.) This app was developed for many years, the software modules were written using JavaScript, jQuery, Angular, React, Handlebars as well as the HTML templating engine Thymeleaf on the server. Nothing unusual, right?

From the user’s perspective, this was one workflow that consisted of several steps resulting in configuring and pricing the car based on selected options. But internally, this process was switching from one module to another, and each module would need to know what was selected in the previous step to show the available options.

In other words, each module would need to know the current state of the app. Depending on the software used in any particular module, the current user’s selections were stored using one of the following places:

* URL parameters
* HTML data attributes
* Browser’s local and session storages
* Angular services
* React store

New requirements were coming in, new JIRA tickets were created and assigned, and we’d start implementing them. Time and time again, implementing a seemingly simple new requirement would turn into a very time consuming and expensive task. Good luck in explaining to your manager why showing the price in page B would take a half day if this price was already known in page A. The thing is that the state object used in page B didn’t expect to have the price property, and if in page A the price was a part of the URL, page B was expecting to get the current state from the local storage.

Re-writing an app from scratch was not an option, but it would be so much easier if the app state was implemented in a uniform way and stored in a single place!

While the Redux is widely used in the web apps developed with the React framework, for Angular apps you can use the ngrx library that also implements the unidirectional data flow and can be used for implementing the app state management.
While the Redux API is simple, the ngrx is not. The reason is that ngrx is a combination of Redux and RxJS libraries that offers more than just keeping track of the round-trips between the UI and the app state. With ngrx, you can inject the code that communicates with external services into the data flow. Also, you can monitor the state of the router.

I’m planning to write a series of blogs to present ngrx, so it wouldn’t require a Ph.D. to master it. If you can’t wait, consider enrolling in our online workshop on using ngrx for state management in Angular apps. You’ll need to invest 7 hours of your time, but this may save you a lot more time in the long run.