Electron alternatives: Exploring NodeGUI and React NodeGUI
Tags: node, nodegui, react, javascript
Published: 2019-10-14 19:35:22

---
title: Electron alternatives: Exploring NodeGUI and React NodeGUI
published: true
date: 2019-10-14 13:00:47 UTC
tags: node,nodegui,react,javascript
canonical_url: https://blog.logrocket.com/electron-alternatives-exploring-nodegui-and-react-nodegui/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/y9y55y8v07sfvpip749n.jpeg
---
**Written by [Siegfried Grimbeek](https://blog.logrocket.com/author/siegfriedgrimbeek/)**✏️

## Introduction

In this post we will explore the freshly released NodeGUI framework, with the main focus on the React NodeGUI module.

To do this, we are going to develop a system utility monitor application that will work on Linux, Mac, and Windows operating systems.

## What is the NodeGUI framework?

Similar to Electron, [NodeGUI](https://github.com/nodegui/nodegui) is an open source library for building cross-platform native desktop applications with JavaScript and CSS-like styling. NodeGUI apps can run on Mac, Windows, and Linux from a single codebase.

What differentiates it from Electron is that it is powered by [Qt5](https://www.qt.io/), which is excellent for performance and memory, but it does force one to then use their components instead of HTML, as with Electron.

From the NodeGUI [release announcement](https://blog.atulr.com/nodegui-intro/):

> NodeGUI is powered by Qt5 [💚](https://s.w.org/images/core/emoji/12.0.0-1/72x72/1f49a.png) which makes it CPU and memory efficient as compared to other chromium based solutions like electron. … NodeGUI wants to incorporate everything that is good about Electron: The ease of development, freedom of styling, Native APIs, great documentation, etc. At the same time NodeGUI aims to be memory and CPU efficient.

**React NodeGUI** enables developers to build performant native and cross-platform desktop applications with native React and powerful CSS-like styling.

We will make use of the [react-node-gui-starter](https://github.com/nodegui/react-nodegui-starter) project to bootstrap our application and get up and running quickly.

## Prerequisites

To follow along with this tutorial, you will need to have [Node](https://nodejs.org/en/) installed, an [IDE](https://ourcodeworld.com/articles/read/200/top-7-best-free-web-development-ide-for-javascript-html-and-css), and a terminal application (I use [iTerm2](https://www.iterm2.com/) for Mac and [Hyper](https://hyper.is/) for Windows).

The application will be built with TypeScript, React, and CSS, so basic knowledge will be handy but is not required as we will walk through every aspect.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## System utility monitor application

We will build a simple application that will dynamically display an operating system’s CPU, memory, and disk space, as well as some additional statistics related to the operating system.

With the application, we aim to cover the following:

- Basics of NodeGUI
- Basics of React NodeGUI
- Node core integration with NodeGUI
- Some caveats of the above

The end result will look as follows:

![Final Application On MacOS](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/10/final-application-mac-os.png?resize=494%2C485&ssl=1)<figcaption id="caption-attachment-8234">Our final application on macOS.</figcaption>

## Let’s write some code

As we will be using the [react-node-gui-starter](https://github.com/nodegui/react-nodegui-starter) project, we can get started by running the following code in your terminal application, which will clone the starter application:

```jsx
# Clone this repository
git clone https://github.com/nodegui/react-nodegui-starter

# Go into the repository
cd react-nodegui-starter

# Install dependencies
npm install
```

Additionally, we will need to install one more npm packages that will allow us to access our systems information:

```jsx
npm i node-os-utils
```

> node-os-utils is an operating system utility library. Some methods are wrappers of Node libraries, and others are calculations made by the module.

### Application scripts and development

The starter application offers a few npm scripts that we can run:

```jsx
"build": "webpack -p",
"start": "webpack && qode ./dist/index.js",
"debug": "webpack && qode --inspect ./dist/index.js",
"start:watch": "nodemon -e js,ts,tsx --ignore dist/ --ignore node_modules/ --exec npm start"
```

For development, we will run the last command:

```jsx
npm run start:watch
```

This will launch the application and also allow for hot reloading whilst developing. After running the above command, you may have noticed a new window load. This window is your shiny new cross-platform React NodeGUI desktop application, which may not look like much at the moment, but we are about to change that.

### Globals and systems details helper

The first thing that we want to do is to create a `globals.ts` file, where we will store some global information related to our application. In the `src` directory, create a directory called `helpers`, and within the `directory`, create a file called `globals.ts` and add the following code:

```jsx
const colors = {
    red: '#FF652F',
    yellow: '#FFE400',
    green: '#14A76C'
}

const labels = {
    free: 'Free',
    used: 'Used'
}

export const globals = {      
    colors,
    labels
}
```

In the above code snippet, we create two objects, `colors` and `labels`. These are added to the `globals` object, which is then exported.

Notice that we only use the colors and labels variable names in the globals object; this is the Object property value shorthand in ES6.

If you want to define an object whose keys have the same name as the variables passed in as properties, you can use the shorthand and simply pass the key name.

The [`export`](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) statement is used when creating JavaScript modules to export functions, objects, or primitive values from the module so they can be used by other programs with the [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) statement.

Next, we can put the `globals.ts` file to use in the `systemDetails.ts` file, which we can also create in the `helpers` directory:

```jsx
// Import External Dependencies
const osu = require('node-os-utils')

// Destructure plugin modules
const {os, cpu, mem, drive} = osu
 
// Import Globals
import { globals } from "./globals"
 
// Use ASYNC function to handle promises
export const systemDetails = async () => {
    // Static Details
    const platform = cpu.model()
    const operatingSystem = await os.oos()
    const ip = os.ip()
    const osType = os.type()
    const arch = os.arch()

    // CPU Usage
    const cpuUsed= await cpu.usage()
    const cpuFree = await cpu.free()

    // Memory Usage
    const memUsed = await mem.used()
    const memFree = await mem.free()

    // Disk Space Usage
    const driveInfo = await drive.info()
    const memUsedPercentage = memUsed.usedMemMb / memUsed.totalMemMb * 100
    const memFreePercentage = memFree.freeMemMb / memFree.totalMemMb * 100

    const systemInformation = {
      staticDetails: {
        platform,
        operatingSystem,
        ip,
        osType,
        arch
      },
      cpuDetails: {
        cpuUsed: {
          usage: cpuUsed,
          label: globals.labels.used,
          color: globals.colors.red
        },
        cpuFree: {
          usage: cpuFree,
          label: globals.labels.free,
          color: globals.colors.green
        }
      },
      memoryDetails: {
        memUsed: {
          usage: memUsedPercentage,
          label: globals.labels.used,
          color: globals.colors.red
        },
        memFree: {
          usage: memFreePercentage,
          label: globals.labels.free,
          color: globals.colors.green
        }
      },
      driveDetails: {
        spaceUsed: {
          usage: driveInfo.usedPercentage,
          label: globals.labels.used,
          color: globals.colors.red
        },
        spaceFree: {
          usage: driveInfo.freePercentage,
          label: globals.labels.free,
          color: globals.colors.green
        }
      }
    }
    return systemInformation
}
```

This may seem like a lot, but there is actually not so much going on. We will break down the code, line by line.

Firstly, we require the [node-os-utils](https://www.npmjs.com/package/node-os-utils) nom package, which we will use to get all our system information.

As stated by the package description, “Some methods are wrappers of node libraries and others are calculations made by the module,” meaning the package relies mainly on native Node.js libraries, which makes it very compatible with NodeGUI. Read more about this [here](https://docs.nodegui.org/#/tutorial/application-architecture?id=using-nodejs-apis).

Next, we use [JavaScript ES6 destructuring](https://hacks.mozilla.org/2015/05/es6-in-depth-destructuring/) to assign variables to functions that we will be using from the node-os-utils package.

Next, we import the `globals` object that we created ourselves. Just like we used the export statement in the `globals.ts` file, we now use it again, but this time to export the ASYNC function `systemDetails`.

The node-os-utils library mostly uses [JavaScript with ES6 promises](https://alligator.io/js/promises-es6/) to return data, which allows us to retrieve that data using an [a](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)[sync/](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)[a](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)[wait function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function). This allows us to write completely synchronous-looking code while performing asynchronous tasks behind the scenes.

I find that using async/await functions lead to very clean, concise, and readable code, so if you are not using them already, definitely check it out. Here is an [awesome video explanation of](https://www.youtube.com/watch?v=568g8hxJJp4) [a](https://www.youtube.com/watch?v=568g8hxJJp4)[sync/](https://www.youtube.com/watch?v=568g8hxJJp4)[a](https://www.youtube.com/watch?v=568g8hxJJp4)[wait](https://www.youtube.com/watch?v=568g8hxJJp4).

We use the node-os-utils library to get our system’s information. Notice that we use the `await` operator in front of some function calls; these are the functions returning a promise. In the node-os-utils libraries description, you can see exactly what each function call returns.

![Functions In node-os-utils](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/10/node-os-utils-functions.png?resize=743%2C329&ssl=1)<figcaption id="caption-attachment-8237">node-os-utils functions.</figcaption>

We then use all the values returned from the function calls to create the `systemInformation` object, which is returned by the `systemDetails` function.

We are now ready to use `systemInformation` and create the application interface.

### Application interface and design

As you may have noticed, at this stage, our application does not look like much — but we are about to change that.

In the `src` directory of our application, create a `components` directory and the following three component files:

- `InnerContainer.tsx`
- `StatsColumn.tsx`
- `StatsRow.tsx`

Next, we will need to update the `index.tsx` file in the `src` directory, and instead of providing all the code, I shall provide snippets to be added with explanations along the way.

To start, let’s remove all the code that we will not use for our application, leaving us with an clean `index.tsx` file, as below:

```jsx
// Import External Dependencies
import {Window, Renderer, View, Text} from "@nodegui/react-nodegui"
import React, { useState, useEffect } from "react"

// Import System Details
import { systemDetails } from "./helpers/systemDetails"

// Application width and height
const fixedSize = { width: 490, height: 460 }

// Function React Component
const App = () => {
  return (
    <Window minSize={fixedSize} maxSize={fixedSize} styleSheet={styleSheet}>
      <View id="container">
        <Text id="header">System Utility Monitor</Text>
      </View>
    </Window>
  )
}

// Application Stylesheets
const styleSheet = `
  #container {
    flex: 1;
    flex-direction: column;
    min-height: '100%';
    align-items: 'center';
    justify-content: 'center';
  }
`

// Render the application
Renderer.render(<App />)
```

If you have worked with React Native before, the above syntax might seem familiar: similar to React Native, we don’t have the freedom to work with HTML. Instead, we work with predefined components (`View`, `Text`, etc.) provided by the framework.

In the above code, we once again import modules and functions using the JavaScript ES6 destructuring syntax.

We then declare a constant, `fixedSize`, which we will use to assign a minimum and maximum width to our application window.

We then create a functional React component where we will build the application. This tutorial will not explain the basics of React, but you can get a beginner’s tutorial [here](https://www.youtube.com/watch?v=dGcsHMXbSOA). This was one of the few video tutorials that make use of React Hooks, which we will use.

If you want to go deeper into React theory, here is an excellent article detailing the intricacies of [React](https://www.robinwieruch.de/react-function-component) [functional](https://www.robinwieruch.de/react-function-component) [c](https://www.robinwieruch.de/react-function-component)[omponents](https://www.robinwieruch.de/react-function-component). Also check out the [official React documentation](https://reactjs.org/docs/hooks-intro.html) on React Hooks, which is available from React 16.8 and are an excellent addition to the framework.

The first component from the NodeGUI React framework is the [`<Window/>`](https://docs.nodegui.org/#/api/QMainWindow) component.

> A `QMainWindow` provides a main application window. Every widget in NodeGui should be a child/nested child of QMainWindow. QMainWindow in NodeGui is also responsible for FlexLayout calculations of its children.

We provide the `<Window/>` component `minSize`, `maxSize`, and `styleSheet` props. The `styleSheet` constant is declared on line 22.

Nested within the `<Window/>` component is a [`<View/>`](https://docs.nodegui.org/#/api/QWidget) component, and within it is a [`<Text/>`](https://docs.nodegui.org/#/api/QLabel) component.

`<View/>` component:

> A `QWidget` can be used to encapsulate other widgets and provide structure. It functions similar to a `div` in the web world.

`<Text/>` component:

> A `QLabel` provides ability to add and manipulate text.

We then declare a `styleSheet` constant, which is a template literal string.

> Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them. They were called “template strings” in prior editions of the ES2015 specification.

Styling the application proved to be rather tricky, as not all CSS properties are supported by the NodeGUI framework, and in some cases, one needs to refer to [Qt Documents](https://doc.qt.io/archives/qt-4.8/stylesheet-reference.html#list-of-properties) to see exactly what one can use.

For example, the property `overflow:scroll` does not exist in Qt CSS, so one needs to implement other workarounds for this functionality as per this [GitHub issue thread](https://github.com/nodegui/react-nodegui/issues/22).

Regarding flexbox support, the NodeGUI framework supports all properties and all layouts as per the [Yoga Framework](https://yogalayout.com/), which is also used by frameworks like React Native and ComponentKit.

Lastly, we render our application.

Now that the base of our application is in place, we will need to integrate the system information and display it using the components we created.

### Initial data object for React Hooks

Before we can use the system data, we will need an initial data object, which the application will use before being populated with data returned from the `systemDetails` function. In the `helpers` directory, create a new file `initialData.ts` and add the following code:

```jsx
export const initialData = {
    staticDetails:{
      platform: 'Loading System Data...',
      operatingSystem: '',
      ip: '',
      osType: '',
      arch: ''
    },
    cpuDetails:{
      cpuUsed: {
        usage: '',
        label: 'Loading',
        color: ''
      },
      cpuFree: {
        usage: '',
        label: 'Loading',
        color: ''
      }
    },
    memoryDetails:{
      memUsed: {
        usage: '',
        label: 'Loading',
        color: ''
      },
      memFree: {
        usage: '',
        label: 'Loading',
        color: ''
      }
    },
    driveDetails: {
      spaceUsed: {
        usage: '',
        label: 'Loading',
        color: ''
      },
      spaceFree: {
        usage: '',
        label: 'Loading',
        color: ''
      }
    }
  }
```

As you can see this mimics the `systemInformation` object which is returned by the `systemDetails` function. Lets add this to the `index.ts` file with as follows:

```jsx
...
// Import System Details
import { systemDetails } from "./helpers/systemDetails"
import { initialData } from "./helpers/initialData"
...
```

### Putting the data to use

Cue React Hooks, probably one of my favorite developments in the JavaScript ecosystem in the last couple of years. It allows for clear and concise code that is very readable and maintainable.

Let’s gets started by implementing the React `setState` Hook that we imported earlier. Add the following code inside the **App** functional React component:

```jsx
  // Array destructure data and setData function
  const [data, setData] = useState(initialData)
```

There is a lot to unpack here, especially if you are new to React Hooks. Instead of trying to explain it all here, I am including a video as a quick introduction course:

{% youtube mxK8b99iJTg %}

If we `console.log()` the data constant, we will see that our `initialData` object has been assigned to the data constant.

Now let’s use some destructuring again to assign the variables we will need for the static data within our application:

```jsx
//Get Static Data
  const {platform, operatingSystem, ip, osType, arch} = data.staticDetails
```

Currently, the `data` constant is still pointing to the `initialData` object we created. Let’s use the `useEffect()` Hook to update our state with data from the `systemsDetail` function. We can do this by adding the following code to the `index.tsx` file, right after the `useState()` Hook:

```jsx
...
const [data, setData] = useState(initialData)

useEffect(() => {
  const getSystemData = async () => {
    const sysData : any = await systemDetails()
    setData(sysData)
  }
  getSystemData()
})

//Get Static Data
...
```

Now if we now `console.log()` the data constant, we will see that it is constantly being updated with new data!

Once again, we will not go into the theory behind the code, but definitely read up on the [`useEffect()` Hook and async/await functionality](https://dev.to/n1ru4l/homebrew-react-hooks-useasynceffect-or-how-to-handle-async-operations-with-useeffect-1fa8).

We can now add the following code below the application header, which will display the system platform:

```jsx
<Text id="subHeader">{platform}</Text>
```

The base foundation for our application has been laid. All we need to do now is the construction and decoration.

### Styling and components

Let’s start by replacing the `styleSheet` constant in the `index.tsx` file with the following code:

```jsx
// Application Stylesheets
const styleSheet = `
  #container {
    flex: 1;
    flex-direction: column;
    min-height: '100%';
    height: '100%';
    justify-content: 'space-evenly';
    background-color: #272727;
  }
  #header {
    font-size: 22px;
    padding: 5px 10px 0px 10px;
    color: white;
  }
  #subHeader {
    font-size: 14px;
    padding: 0px 10px 10px 10px;
    color: white;
  }
`
```

So far this is pretty standard CSS styling, but we will see some edge cases as we proceed.

Let’s populate our first component, the `StatsRow.tsx` file, with the following code:

```jsx
// Import External Dependencies
import React from 'react'
import {View} from "@nodegui/react-nodegui"

export const StatsRow = (props: { children: React.ReactNode; }) => {
  return (
      <View id="systemStats" styleSheet={styleSheet}>
          {props.children}
      </View>
  )
}

const styleSheet = `
  #systemStats {
    width: 470;
    height: 180;
    flex: 1;
    flex-direction: row;
    justify-content: 'space-between';
    margin-horizontal: 10px;
  }
`
```

We have covered most of the the code above, but one thing to note is the [special React prop](https://reactjs.org/docs/react-component.html#props) `props.children` and the syntax for using it with TypeScript. This [article](https://medium.com/@martin_hotell/react-children-composition-patterns-with-typescript-56dfc8923c64) has a very in-depth explanation regarding React children composition patterns in TypeScript.

Let’s import the `StatsRow` component by adding the following code to the `index.tsx` file:

```jsx
...
// Import Components
import {StatsRow} from "./components/StatsRow"
...
```

We will use the `StatsRow` component to create two rows in our application, but before we use it, let’s first populate the `innerContainer.tsx` by adding the following code:

```jsx
// Import External Dependencies
import React from 'react'
import {View, Text} from "@nodegui/react-nodegui"

// Set Types
type InnerContainerColumnProps = {
    title: string
}

export const InnerContainer: React.FC<InnerContainerColumnProps> = props => {
  // Desctructure props
  const {title, children} = props

  return (
      <View id="innerContainer" styleSheet={styleSheet}>        
          <Text id="headText">{title}</Text>
          <View id="stats">
            {children}
          </View>
      </View>
  )
}

const styleSheet = `
  #innerContainer {
    height: 180;
    width: 230;
    background: #111111;
    border-radius: 5px;
  }
  #stats {
    flex-direction: row;
    align-items: 'flex-start';
    justify-content: 'flex-start';
  }

  #headText {
      margin: 5px 5px 5px 0;
      font-size: 18px;
      color: white;
  }
`
```

Again, we covered most of the above code already. Notice that we need to take some extra measures to accommodate TypeScript in the React components — [this](https://fettblog.eu/typescript-react/components/) is an excellent article explaining the best ways of making the components and TypeScript work together.

Let’s add it to the `index.tsx` file with the following code:

```jsx
...
// Import Components
import {StatsRow} from "./components/StatsRow"
import {InnerContainer} from "./components/InnerContainer"
...
```

Let’s finish up our final component, `StatsColumn.tsx`, before tying it all together in the `index.tsx` file. I will break up the code into two parts, which should be combined: the first part is the component without the styles, and the second part is the styles:

```jsx
// Import External Dependencies
import React from 'react'
import {View, Text} from "@nodegui/react-nodegui"

// Set Types
type StatsColumnProps = {
    label: string,
    usage: number,
    color: string
}

export const StatsColumn: React.FC<StatsColumnProps> = props => {
    // Destructure props
    const {usage, color, label} = props

    // Create Label with usage amount and percentage
    const percentageTextLabel = `${label} ${Math.round(usage * 100) / 100}%`

    // Create Dynamic Style Sheet
    const dynamicStyle = `
        height: ${usage};
        background-color: ${color};
    `

    return (
        <View id="statsContainer" styleSheet={statsContainer}>
            <View id="columnContainer" styleSheet={columnContainer}>   
                <View id="innerColumn" styleSheet={dynamicStyle}></View>
            </View>
            <Text id="statsLabel" styleSheet={statsLabel}>{percentageTextLabel}</Text>
        </View>
    )
}
```

We use this component to create the graph effect, as you can see on the final application screen grab.

We pass the `label`, `usage`, and `color` props to the component, which we will use to dynamically update the component.

Below the above code, add the style code below:

```jsx
const statsContainer = `
    #statsContainer {
        height: '140';
        text-align:center;
        justify-content: 'center';
        align-items: 'center';
        justify-content: 'space-between';
        width: 100%;
        flex: 1 0 100%;
        margin-horizontal: 5px;
    }
`

const columnContainer = `
    #columnContainer{
        height: 100%;
        flex: 1 0 100%;
        flex-direction: column-reverse;
        background-color: #747474;
        width: 100%;
    }
`

const statsLabel = `
    #statsLabel {
        height: 40;
        color: white;
        font-size: 14px;
        width: 100%;        
        qproperty-alignment: 'AlignCenter';
        color: white;
    }
`
```

Note how each style property is declared as its own constant. This is another way to create `styleSheet` blocks; I doubt it makes a difference, it is more a developer preference.

You may also have noticed the CSS property `qproperty-alignment: 'AlignCenter';` and thought you have not seen this before. And you are totally right — this is a Qt property and it is used to align text. It took me some time to figure this out. [Here](https://doc.qt.io/qt-5/stylesheet-syntax.html) is a Qt style sheet syntax reference link, which could assist you if you encounter a caveat like this.

That’s it for the components. Let’s get to work on the `index.tsx` file.

### Let’s wrap this up

Let’s import our final component into the `index.tsx` file:

```jsx
// Import Components
import {StatsRow} from "./components/StatsRow"
import {InnerContainer} from "./components/InnerContainer"
import {StatsColumn} from "./components/StatsColumn"
```

Add the following styles to the `styleSheet` constant in the `index.tsx` file:

```jsx
...
  #subHeader {
    font-size: 14px;
    padding: 0px 10px 10px 10px;
    color: white;
  }

  #headText {
    margin: 5px 5px 5px 0;
    font-size: 18px;
    color: white;
  }
  #infoText {
    padding: 5px 0 0 5px;
    color: white;
  }
  #informationContainer {
    height: 180;
    width: 230;
    background: #111111;
    border-radius: 5px;
  }
...
```

Now for the first bit of meat on our application. Below the `<Text id="subHeader">` component in the `index.tsx` file, add the following code:

```jsx
...
<StatsRow>
   <View id="informationContainer" styleSheet={styleSheet}>
      <Text id="headText">System Information</Text>
      <Text id="infoText">{operatingSystem}</Text>
      <Text id="infoText">{osType}</Text>
      <Text id="infoText">{ip}</Text>
      <Text id="infoText">{arch}</Text>
    </View>
</StatsRow>
...
```

The above code is pretty self-explanatory, but notice that we need to reference the `styleSheet` in the `<View id="informationContainer">` , even after referencing it in the main `<Window>` component. This is due to a caveat where the styles are not inherited by children components.

If you are “still watching” the application, you will now see that, for the first time, our application is starting to resemble an actual application.

Let’s add the code to create the “charts.” Below the `useEffect()` Hook, add the following code:

```jsx
const renderCpuDetails = () => {
  const cpuDetails = data.cpuDetails
  return Object.keys(cpuDetails).map((key) => {
      const stat = cpuDetails[key]
      return <StatsColumn label={stat.label} usage={stat.usage} color={stat.color}  />
  })
}

const renderMemoryDetails = () => {
  const memDetails = data.memoryDetails
  return Object.keys(memDetails).map((key) => {
      const stat = memDetails[key]
      return <StatsColumn label={stat.label} usage={stat.usage} color={stat.color}  />
  })
}

const renderDriveDetails = () => {
  const driveDetails = data.driveDetails
  return Object.keys(driveDetails).map((key) => {
      const stat: any = driveDetails[key]
      return <StatsColumn label={stat.label} usage={stat.usage} color={stat.color}  />
  })
}
```

In the above code, we loop over the respective object keys and then use the values as props for the `<StatsColumn/>` component.

We can then use these functions in our code by updating the `index.tsx` file with the following:

```jsx
<StatsContainer>
    <View id="informationContainer" styleSheet={styleSheet}>
      <Text id="headText">System Information</Text>
      <Text id="infoText">{operatingSystem}</Text>
      <Text id="infoText">{osType}</Text>
      <Text id="infoText">{ip}</Text>
      <Text id="infoText">{arch}</Text>
    </View>
  <InnerContainer title={"Disk Space"}>
    {renderDriveDetails()}
  </InnerContainer>
</StatsContainer>
<StatsContainer>
  <InnerContainer title={"CPU Usage"}>
    {renderCpuDetails()}
  </InnerContainer>
  <InnerContainer title={"Memory Usage"}>
    {renderMemoryDetails()}
  </InnerContainer>
</StatsContainer>
```

In the above code, we execute the three previously declared functions, which, in turn, render the Disk Space, CPU Usage, and Memory Usage columns.

That wraps up our application, the source code for everything can be found here on [GitHub](https://github.com/siegfriedgrimbeek/NodeGUI-System-Utility-Library).

## Conclusion

Having been announced for release just two months ago, React NodeGUI is still very much in their infancy, but with more than 3,500 stars on GitHub at the time of writing, it definitely shows a lot of promise.

As a web developer, one might be very accustomed to writing HTML code and switching to the React Native-like component approach does demand a bit of a mindset shift since one does not have the freedom of HTML.

Some components, like the Qt Scroll Area, still need to be ported to the framework, so if one is to start a project with the framework, first thoroughly research the limitations and also keep an eye on the issues on GitHub.

The last bit of advice is to not take anything for granted. To ensure a truly cross-platform desktop experience, make sure that all CSS properties are explicitly declared — this means all colors, fonts, font-sizes, etc. are all specified, as it may be interpreted differently by different operating systems.
* * * 
**Editor's note:** Seeing something wrong with this post? You can find the correct version [here](https://blog.logrocket.com/electron-alternatives-exploring-nodegui-and-react-nodegui/).

## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *
The post [Electron alternatives: Exploring NodeGUI and React NodeGUI](https://blog.logrocket.com/electron-alternatives-exploring-nodegui-and-react-nodegui/) appeared first on [LogRocket Blog](https://blog.logrocket.com).