Animating a React Component

I have always been a fan of having user interfaces that are smooth for the eyes. One way to do it is to animate element that moves from one position to another one. When I was working at Microsoft in VSTS (Visual Studio Team Services) I developed the animation around widgets. A widget is a small block of a dashboard and one task possible is to edit this one. Instead of having the edit panel coming in place and having a blunt experience. I animated the panel to come from the right edge of the browser inside the viewport and also animating the widget to move from its position in the dashboard in the middle of the screen while blurring the background. The experience was great. The panel wasn’t hiding a lot the viewport, the user knew exactly where was the widget before the edition and it was clear which widget was in an edition. This was done many years ago, all in JQuery with some CSS animation. It was dirty by today’s standard but not a huge feat to accomplish in my perspective. Today, I am not relying on JQuery but on React and the process for something is similar with the difference that it requires a little bit more thought.

React is great on many points but if you want to customize how a component change from a position/size to another it can be mesmerizing. The reason is that React when receiving new information will render and the rendered component will be at its final position. In this article, I will cover how to handle the case of a React’s component that needs to move its “left” and “top” position but it could be any property you want.

Before jumping in the code, let’s describe what we will do. The idea is to get the actual data right before we are getting the new value and save a copy of it inside the component before it renders. A good place is componentWillReceiveProps where you can access the DOM element by reference and save a copy of it before the new props are propagated into the whole React’s lifecycle of your component. React render function does not paint to the screen when the render function is invoked. It is once the componentDidUpdate is called that the browser paint. With the information in mind, and the data saved in the componentWillReceiveProps we can access the before and after the position/size of a component. The before being gathered in componentWillReceiveProps and after in render function.

What you can do is to create one variable to hold the value that change and that you care for your animation. You also need one variable to have a reference to the HTML element. This should be a variable in the class component and not in the state. Changing the state invokes the lifecycle of your component to render again which is not required in that case. In the following example, I am saving my HTML element that I want to animate with the left and top position.

private domCluster: HTMLDivElement | null = null;
private lastLeftPosition: number = 0;
private lastTopPosition: number = 0;

The next step is to save the actual value in the variable of the class. In my example, I’ll get from the saved reference of the HTML element the top and left position using the JavaScript function getBoundingClientRect().

public componentWillReceiveProps(nextProps: FillWindowsClusterProps): void {
   if (this.domCluster !== null) {
      const coord = this.domCluster.getBoundingClientRect();
      this.lastLeftPosition = coord.left;
      this.lastTopPosition = coord.top;
   }
}

The next function to define is the render. The render function has the role to set up the component at its final place and to set up the reference to the HTML element.

public render(): JSX.Element {
    return <div
        key={"myComponentName_" + this.props.elementUniqueId}
        ref={(e) => this.domCluster = e}
        style={
            {
                left: this.props.left,
                top: this.props.top
            }
        }
    >
        Your Component
    </div>;
}

The last React piece is in the code in the componentDidUpdate. This code will calculate the difference between the final position that we will get again using the getBoundingClientRect() from the element generated by the render function and the last position saved from the componentWillReceiveProps.

public componentDidUpdate(previousProps: FillWindowsClusterProps): void {
    if (this.domCluster !== null) {
        const coord = this.domCluster.getBoundingClientRect();
        const deltaPositionLeft = this.lastLeftPosition - coord.left;
        const deltaPositionTop = this.lastTopPosition - coord.top;
        if (this.domCluster !== null) {
            this.domCluster.style.transform = `translate(${deltaPositionLeft}px, ${deltaPositionTop}px)`;
            this.domCluster.style.transition = "transform 0s";
        }
        requestAnimationFrame(() => {
            if (this.domCluster !== null) {
                this.domCluster.style.opacity = "1";
                this.domCluster.style.transform = "";
                this.domCluster.style.transition = "transform 850ms, opacity 800ms";
            }
        });
    }
}

The heavy lifting is done by CSS. The idea is to use translate on the x and y coordinates and to set the value back to the old position. Then, we are using requestAnimationFrame to tell the browser that on the next rendering loop to remove the transform setting back the position to the final one (the one determined in the last render).

In the end, the animation will work flawlessly. The user will not see the trick we just put in place. In reality, we had a life cycle in React that position the element at its final place but we used CSS to return the element back into its original place — the place the component was before the render. And then we let the browser render the element that has a style that put immediately the component into its initial place with an animation to let go the component into its final position.

From a JQuery perspective, it’s a lot of more work with React. However, that is the cost to pay to have an optimized framework that takes care of the DOM/HTML for you. In that particular case, where the HTML must be accessed, there is a little tax to set up everything correctly. However, since most of the React’s components are not animated and that the core goal is to let React handle the painting it is a small pain for an overall nice performance gain.

How to set and read bitwise enum values in TypeScript

Using a bitwise number in an enum is the way to have a single variable with many potential values. A canonical example is to have a status that can be in several states at the same time. I recently create a generic interface in TypeScript to wrap an entity (any business logic type) to add additional data like the status.

enum Status {
    Unknown = 0,
    New = 1 << 0,
    Dirty = 1 << 1,
    InError = 1 << 2,
    Processing = 1 << 3,
    PersistedEntity = 1 << 4
}

The similar enum can use a direct number that represents all power of 2 (2^0, 2^1, 2^2, 2^3, 2^4). The importance is to have a number that in binary occupy one spot (0, 10, 100, 1000, 10000).

enum Status {
    Unknown = 0,
    New = 1,
    Dirty = 2,
    InError = 4,
    Processing = 8,
    PersistedEntity = 16
}

The idea is any variable of this enum type can assign a value directly or combine many values. To assign a single value, the use of the equal sign is good as you would do with an amount that is not bitwise. However, using the equal sign override any previous value assigned to the variable.

let value: Status = Status.New;
console.log("Only new", value);
value = Status.New | Status.Dirty; // New + Dirty
value = Status.New; // Only new

A value can hold more than a single value. In the case that we want to persist the existing value intact and you need to use the sign |=. To remove a particular status you need to use &= ~. Using these operators will swap the value at the right position in its binary format without affecting the remaining parts of the number.

value |= Status.Processing;
console.log("New and processing", value);
console.log("Is it new?", value === Status.New); // Not the right way
console.log("Is it new?", Status.New === (value & Status.New)); // Right way
console.log("Is it processing?", Status.Processing === (value & Status.Processing)); 
value &= ~Status.Processing;

Finally, to check if the variable is of a particular status you must use the triple equal with the ampersand to the value you want to check against. This is often the mistake I see. People are using the triple equal or are using the ampersand without comparing it back to the desired value. The simple form of comparison is a mistake. The ampersand returns a number, not a boolean. The comparison needs to be against the value that we want to check.

console.log("Is it new?", Status.New === (value & Status.New)); 
console.log("Is it processing?", Status.Processing === (value & Status.Processing)); 

The output of the code all the previous code gives:

Only new 1
New and processing 9
Is it new? false
Is it new? true
Is it processing? true
Is it new? true
Is it processing? false

Using bitwise number is harder to grasp at first glance and open code to error more easily even with TypeScript. It is recommended to use bitwise wisely and not to abuse it.

Simple Pattern to use Highchart and React

At the time I am compositing this entry, Highchart doesn’t collaborate naturally in a React project. There is an open source project available but it is not part of the official release. However, using directly the library from Highchart into your TypeScript and React project is not a huge burden. In this article, we will see how to create a React component that uses Highchart.

The first step is to get the official library and the definition file. The types are not in the main repository and are a major version late. However, it was enough in my experience to work. You need to NPM install “highcharts” and “@types/highcharts”.

You will need to create a new TSX file and import one or many packages. The number of packages depends on what you want to do with HighChart. If you need to use the exporting capability, you will need to import an additional module. If you need the offline flavor of exporting, you will need also to import a package. For the completeness of the example, let’s get them all.

import Highcharts, { CSSObject, Options, SeriesObject, PlotBands } from "highcharts";
import Exporter from "highcharts/modules/exporting";
import OE from "highcharts/modules/offline-exporting";

The Exporting and OE are functions. They must be applied to the HightCharts function right below you imports.

Exporter(Highcharts);
OE(Highcharts);

The next step is to create a React component that will have a componentDidUpdate, a render, and a componentDidMount. Also, the component must have one reference to Highchart and one other reference to the HTML container. The container may be used for adding dynamic animation with CSS and also to indicate where to inject the Highchart component. The Highchart component reference will be used to push data or user’s options during the lifetime of the component.

private hightChartContainer: HTMLDivElement | null = null;
private highChartControl: Highcharts.ChartObject | undefined = undefined;

The render function creates the container that hosts the Highchart control.

    public render(): JSX.Element {
        const isChartVisible = this.props.source.graphData !== undefined;
        const chart = <div
            style={{
                display: (isChartVisible ? "block" : "none")
            }}
            ref={(div) => { this.hightChartContainer = div; }}
        />;
        return <>
            <div
                style={{
                    display: (isChartVisible ? "none" : "flex"),
                }}
            >
                Loading your data
            </div>
            {chart}
        </>;
    }

The render will be executed once and then the componentDidMount function is executed once as well. Meanwhile, the componentDidMount function does the heavy lifting by instantiating the Highchart component. In reality, this function is way bigger than what I am providing. It contains all the configuration you can apply to a Highchart.

public componentDidMount() {
        const that = this;
        if (this.hightChartContainer !== null) {
            Highcharts.setOptions(theme);
            const options: Options = {
                chart: {
                    type: "line",
                },
                series: [],
            };
            this.highChartControl = Highcharts.chart(this.hightChartContainer, options);
            if (this.props.source.graphData !== undefined) {
                this.componentDidUpdate();
            }
        }
    }

Finally, the componentDidUpdate has the role to push the values to the chart. The componentDidMount sets the series to an empty array because the data might not yet be available. However, the componentDidUpdate will be called every time new properties change which make it a good place to update the chart.

public componentDidUpdate() {
        if (this.hightChartContainer !== null && this.highChartControl !== undefined && this.props.source.graphData !== undefined) {
            const data = this.props... // Get your data
            const series: GraphData[] = [];
            while (this.highChartControl.series.length > 0) {
                this.highChartControl.series[0].remove(false);
            }

            // Values dimension represent each series
            scenarioUpdate.addMarker("CreateSeries");
            rawValues.forEach((value: number[], index: number) => {
                const time = data.start + index * data.step;
                for (let iSerie = 0; iSerie < value.length; iSerie++) {
                    if (index === 0) { // Only first time we create series
                        series.push({
                            seriesName: data.legend[iSerie],
                            seriesValues: []
                        });
                    }
                    series[iSerie].seriesValues.push({ time: time, value: value[iSerie] });
                }
            });

            let loopCount = 0;
            series.forEach((serieData: GraphData, index: number) => {
                if (this.highChartControl !== undefined) {
                    const values = serieData.seriesValues.map((d: GraphDataValue) => { loopCount++; return [d.time, d.value]; });
                    this.highChartControl.addSeries({}, false, false);
                    this.highChartControl.series[index].setData(values, false, false, false);
                    this.highChartControl.series[index].update({ name: serieData.seriesName }, false);
                }
            });

            window.requestAnimationFrame(() => {
                window.requestAnimationFrame(() => {
                    if (this.highChartControl !== undefined) {
                        this.highChartControl.reflow(); 
                        this.highChartControl.redraw(); 
                    }
                });
            });
        }
    }

Once again, I removed a lot of the code from which I have been inspired. The goal here is to create all your series but before creating series, we remove all the existing one. In the end, we reflow and redraw which animated the graph. Indeed, a good “shouldComponentUpdate” is required to avoid updating for no reason.

It might look like a lot of code but in reality, it is so close to the Highcharts documentation that it is easy to maintain. The key concept is to have the container that host Highchart build one time and to update the existing one.

My Preparation and Experience of Shift Conference in Croatia

One morning in late February this year, I received an invitation to present at Shift Conference which is the largest developer conference in Southeast Europe. I discussed with my manager, and within few hours I was committing giving a 45 minutes talk. Netflix is excellent in this regard by encouraging its engineers not only to attempt but also to give presentations.

The adventure was just about to start. I needed to create an outline of the subject I wanted to talk, build the code that I presented and finally create the slides. The theme was easy to choose: TypeScript. I have been writing and vouching for the language for a while, and it is always easier to talk about a subject that you believe, and master. The next step was to decide what to talk about TypeScript. The subject can go in many directions and I decided to provide a lot of different features with the goal that any one or two aspects presented would trigger some curiosity among the attendees to have them try TypeScript.

The composition of the outline was carefully done with a primary text for each slide. The writing is required for me since I am not fluent in English like in French. It helped me to have a better idea how to structure my thoughts. I did this step in parallel with the code, and I added to each slide the code file name. The link between the outline’s lines and the code allowed me to go back and forth in change and still be clear when it was the time to build the slide to add the right code with the correct text. The creation took me about two months which I estimate to about 50 hours of time for 60ish slides. I added, modified and removed slides. In the last few weeks, I removed about six slides on topics that were too advanced or harder to grasp for people that never developed with TypeScript. My philosophy was not to confuse but rather to inform. Learning the slides by heart took me about one month. It is easier when you build them to memorize the content. My slides contained almost only code and a title, so it was easy to forget the primary goal or example. In the end, I knew all the slide and could visualize them along with the text. Few days before the event, I had spent about 80 hours. The time includes all the rehearsal which are quite long on a speech of 45 minutes. I was able to split in two the speeches and often practiced only the first half. I also did several rehearsals in my car while driving to and from Netflix — optimizing my time!

I left in the last week of May, two days before the conference. I had to take three planes: San Jose to Los Angeles, Los Angeles to London and then to Split (Croatia). The whole trip is 14 hours inside the aircraft, but with the connections, it is about 18 hours overall. The time doesn’t count the 9 hours of timezone change. It is rough and even more since I was staying only three days before moving back because I was working the next Monday. Even if I had this great opportunity, my primary job at Netflix remains my priority, and I have code to ship for a release soon. No time to do the tourist too much.

Shift organizers did a great job by booking all the planes, taking care of the hotel and the transports. I had nothing to think else than the presentation. I arrived at Split, Croatia, Wednesday evening very late. I barely visited, just enough to grab something to eat and sleep. The next day, my presentation was in the afternoon. I was very tired, slept and went to see the two presentations before me. I went backstage and got briefed rapidly. I went on stage about 20 minutes earlier because of a shorter speech, but it didn’t bother me. I went on stage and I was able to perform my whole presentation in time with two minutes remaining. I forgot some explanations, few examples and looked slightly too much on the screen but overall, I am satisfied with my performance. For some reason, I forgot few slides in my head. I could find many excuses but that wouldn’t change a thing. What I take from this experience is that a lot of preparation is needed for 45 minutes. I would do it again in the future but this is definitely many months of work with always something to tweak.

I had the time to visit Split which is terrific. The city has a lot of historical point of views. People were fascinating to talk, and I had a fun time. I was able to watch about 70% of other presenters speeches too.

It also gave me the opportunity to discuss with other presenters. Many dinners and side events were organized. I was able to talk with Rasmus Lerdorf, the creator of PHP; Luca Cipriani, the CIO of Arduino; Devaris Brown, from Heroku; Eric Schabell from Redhat; John Feminella from Pivotal; Michal Sanger from Kiwi.com; Ivan Burazin from CodeAnywhere (and organizer of the event) and see Hakon Wium Lie, the creator of CSS. It was quite exciting and significant to be able to share with all these people. I also enjoyed having people from the audiences talking about their project and how they were interested in using TypeScript.

To conclude, it was a perfect opportunity, and I am glad I did not hesitate. Even if preparing a speech is time-consuming and require a good investment of days in travel, it worth it. A curious fact is that I got stressed the first few minutes of the presentation, as you can see in the following graph as well as a few days before.

I had started my Fitbit few minutes before entering the stage. Since the person before me finished about 20 minutes earlier, I do not have as many “rest” data point. Normally, I am between 55-65 beats per minute. Right before entering on stage, I was already at 80 bps. My peak during the presentation was 140 bps! Once I get the video, I’ll be able to point with more accuracy what caused the downs and ups of this graph.

TypeScript and Redux Immutability Functions

The actual system I am working in my daily job is using TypeScript, React and Redux. I am not relying on any framework to do the immutability. I am using pure JavaScript cloning mechanism and have unit tests for each of my reducer that makes sure that the instance returned is not the same. It works great, it’s easy to understand, and doesn’t require any dependencies. However, few utility functions ease the whole process mostly when using dictionary which is present everywhere since I an normalizing my data in the Redux store to avoid having any duplicated values.

First, I am using an alias for the index signature just to avoid repeating the square brackets syntax everywhere. This doesn’t provide much but is worth mentioning because all the future function I’ll share use this interface.

export interface GenericMap<T> {
    [id: string]: T;
}

The first useful function is to add into an array an object without mutating this one. This function relies on the array’s function “slice” to return a copy of the array.

export function addInArrayIfNotPresent<T>(array: T[], item: T): T[] {
    let returnArray: T[] = [];
    if (array !== undefined) {
        returnArray = array.slice();
        if (array.indexOf(item) === -1) {
            returnArray.push(item);
        }
    }
    return returnArray;
}

// Usage:
const newReferenceArrayWithItemsAdded = addInArrayIfNotPresent(existingArray, itemsToAdd);

The second function is to add a new element in a map without mutating the existing dictionary. This is useful because it handles the cloning and swap the value into the cloned dictionary.

export function alterImmutablyMap<T>(stateMap: GenericMap<T>, key: number | undefined, modelMember: T): GenericMap<T> {
    if (key !== undefined) {
        const cloneStateMap = Object.assign({}, stateMap);
        cloneStateMap[key] = modelMember;
        return cloneStateMap;
    }
    return stateMap;
}

// Usage:
const newDictionary = alterImmutablyMap(existingDictionary, key, value);

The third function allows changing a property of an existing object in a dictionary. The function is useful if the user change a single property and you do not want to change to extract the current object and manually clone it to set the new value into a new clone of the object.

export function alterImmutablyMapMember<T, K extends keyof T>(stateMap: GenericMap<T>, key: number | undefined, modelMember: K, value: T[K]): GenericMap<T> {
    if (key !== undefined) {
        if (stateMap[key] !== undefined) {
            const cloneStateMap = Object.assign({}, stateMap);
            const modelFromState = Object.assign({}, cloneStateMap[key]) as T;
            if (modelFromState !== undefined) {
                modelFromState[modelMember] = value;
                cloneStateMap[key] = modelFromState;
            }
            return cloneStateMap;
        }
    }
    return stateMap;
}
// Usage:
const newDictionary = alterImmutablyMapMember(existingDictionary, key, member, value);
const newDictionary2 = alterImmutablyMapMember(existingDictionary, 1, "name", "Patrick"); // Change the item 1's property name to Patrick