React Astro - Global state in React using events
Tags: react, javascript, globalstate, hoc
Published: 2019-01-04 23:13:00

---
title: React Astro - Global state in React using events
published: true
description: Global State tool for react that provides simple to use api. Non component drilling an single source of truth.
tags: React,JavaScript,Global State,HOC
---

Blog noob here. 💩

One morning I was bored and decided to start a new project in react. Upon setting up redux I thought of trying something new.

There has been a trend in react blogs lately explaining react's new Hooks API and different ways to implement global state. 
I was wanting to implement my own custom global state solution for a while and thought this was a good opportunity. 

This was partly because I wanted to see if it's possible to make something easy to use and simple to set up. 

Don't get me wrong, redux is great and I don't recommend using the method in this blog for any big scale project... It's not yet thoroughly tested, purely experimental and just for fun at this stage! 

My main goal on this custom implementation would be this:

<ul>
    <li>Single source of truth</li>
    <li>State that would update any components that make use of it</li>
    <li>No component drilling (occurs when parent component passes data to deeply nested children, causing a domino-like update on the dom tree)</li>
</ul>

I sat on it for a while and decided on a possible solution.
I thought Using the EventEmitter class from 'events' in conjunction with a higher order component would provide an ideal solution.

I started by creating the basic structure, as well as a function to initiate the globalState object externally :

```jsx
import React from 'react';
import { EventEmitter } from 'events';

const stateEmitter = new EventEmitter();
stateEmitter.setMaxListeners(0);

export let globalState = {};

export function addGlobalState(stateObj) {
  globalState = { ...globalState, ...stateObj };
}
```
Next up would be to create the core set function:

```jsx
export const setGlobalState = param => {
  const newState = typeof param === 'function' ? param(globalState) : param;

  try {
    for (var key in newState) {
      globalState[key] = newState[key];
      stateEmitter.emit(`astroUpdate:${key}`);
    }
    stateEmitter.emit('astroUpdateState');
  } catch (error) {
    console.log('setGlobalStateError: ', error);
  }
};
```

The `setGlobalState` would take in a plain object, similar to react's `setState` method (the previousState implementation is also used). This would then update the globalState object with the new state object. After updating the state an event would be emitted notifying subscribed listeners that the state has changed.

Next up would be to create the capable HOC function:

```jsx
export default function AstroStateProvider(WrappedComponent, keys = []) {
  return class extends React.Component {
    componentDidMount() {
      if (keys.length > 0) {
        for (const key of keys) {
          stateEmitter.on(`astroUpdate:${key}`, () => {
            this.forceUpdate();
          });
        }
      } else {
        stateEmitter.on('astroUpdateState', () => {
          this.forceUpdate();
        });
      }
    }

    render() {
      let stateToReturn = {};
      if (keys.length > 0) {
        for (const key in globalState) {
          if (keys.includes(key)) {
            stateToReturn[key] = globalState[key];
          }
        }
      } else {
        stateToReturn = globalState;
      }

      return <WrappedComponent {...this.props} astro={stateToReturn} />;
    }
  };
}

```

As you can see above, the hoc simply listens to any changes as set in the `setGlobalState` function and then runs a re-render via `forceUpdate`.
Also, the option exists to only listen to subscribed keys as defined by the second argument `keys` of `AstroStateProvider`.

The hoc then returns the wrapped component and the contents of the globalState object in a prop named `astro`.

This is also kind of an attempt at opensource contribution, so I have created a npm package based on this logic called [React Astro](https://www.npmjs.com/package/react-astro)

Installation, usage, and other minor details can be found there. 

Anyone is also welcome to contribute on the [Github Repo.](https://github.com/LeonVDW/react-astro)

Cheers 🙂