Practical use case for Javascript Function Properties (ReactJS)

TL;DR : Function properties are useful when meta-programming, specifically avoiding minification and mangling of function names

The new UI for CyberSift consists of a number of “widgets” which are interchangeable and can be moved around the screen to cater for a user’s preferred layout. Heavily inspired by Elastic’s Kibana, you can see the end result below:

Interchangeable widgets + dynamic layout

The above is based on the excellent “React Grid Layout” library. In our case, once the “grid change” event fires, we store the current layout in JSON and transmit that to our backend so the user will find their preferred layout on next login.

In a nutshell, we did this by storing two JSON objects: one described the grid layout as required by the library, the other object described which widgets were in which position in the grid. Examining the example layout in the library’s github, we see:

const layout = [
      {i: 'a', x: 0, y: 0, w: 1, h: 2, static: true},
      {i: 'b', x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4},
      {i: 'c', x: 4, y: 0, w: 1, h: 2}
    ];

Note the “i” key, which describes which “div” should be placed in that position. Our goal was so that whenever a user changed a widget in a certain position, the “i” key would also be updated with the corresponding React component name.

Our initial solution was to simply inspect a react component via the console, for example: console.log(<TopSources />). From there we could see that every component has a “type” property, whose “name” key returns the given name of the component, as can be seen below:

Everything worked as expected however a problem cropped up. In production, the layout would break. Empty widgets everywhere! Of course, we were unable to reproduce this in the development environment so it passed through all our tests. It turns out, that in production and only in production, instead of having something like:

const layout = [
      {i: 'TopSources', x: 0, y: 0, w: 1, h: 2},
      {i: 'TopDestinations', x: 0, y: 0, w: 1, h: 2},
...
    ];

we ended up with the following instead:

const layout = [
      {i: 'Ve', x: 0, y: 0, w: 1, h: 2},
      {i: 't', x: 0, y: 0, w: 1, h: 2},
...
    ];

An educated guess led us to the hypothesis that the component names were being minimized by webpack. This turned out to be the case. We needed to find a way to include the component name in such a way as it wouldn’t be minimized. We came across a good solution, which was possible due to functional React. Recall that React allows you to define component using a function, for example at bare minimum we can have:

import React from 'react'

const topSources = () => <div>
     Top Sources Widget
</div>

export default topSources

It turns out that function properties (kindof like static variables for javacript functions) are not minified (see original link here), so we can add a single line to the above code:

topSources.displayName = "topSources"

Inspecting the component in the console we see the new property:

As expected, the ‘displayName’ function property was not minified and resolved this particular bug!

Advertisement