Neox data structure compatible with redux hooks

Neox data structure compatible with redux hooks

What’s Neox?

Neox is a really tiny JavaScript library (just 269B when minified and gzipped!) that exposes a function returning a simple data structure from any given plain JavaScript object.

The problem it solves

While using Immutable to create our Redux reducers, we found an issue in the way it interacts with React’s useEffect hook ("the Effect Hook lets you perform side effects in function components"). As Immutable Maps return a new reference every time the toJS function is called and also a new reference for the inner properties, the callback provided to a useEffect hook was being triggered on every mutation to the reducer, even if the desired property hadn’t changed at all!

In order to solve this, we had to get rid of Immutable (see this issue), but we wanted to avoid changing a lot of code on every reducer. Neox data structure is built to return a new reference every time the toJS function is called but not to change the reference of the inner properties, the callback provided to a useEffect hook is only triggered when the desired property has changed!

Neox data structure overview

First, let’s see how we can use the library to create a simple Neox data structure from an object and store it in a constant called state.

import fromJS from "@neocoast/neox";
const state = fromJS({
loading: false,
user: {
id: 1,
username: "tintef",
},
});
console.log(state);
// Object {values: Map, toJS: function toJS(), set: function ()}

As can be seen, the result of the console.log statement, our state has just three properties:

  • values: Map object containing all the entries from the object passed as a parameter to the fromJS function.
  • toJS: function that returns a new object on each call. This object contains every property inside the values Map.
  • set: handy function to mutate the values property.

But… why this approach?

Long story short we wanted to replace every occurrence of Immutable’s fromJS function with the least effort possible.

We were using the following piece of code to create a reducer:

import { fromJS } from 'immutable';
const intialState = fromJS({
loading: false,
user: {
id: 1,
username: 'tintef',
},
});
export default reducer(state = initialState, action) => {
switch (action.type) {
case 'SET_LOADING':
return state.set('loading', action.payload);
case 'SET_USER':
return state.set('user', action.payload);
}
}

Then, we can access its properties from a React component doing:

import React from 'react';
import { useSelector, shallowEqual } from 'react-redux';
const Component = () => {
const { user } = useSelector(state => state.toJS(), shallowEqual);
...
}

As Neox data structure shares the functions we are using from Immutable Maps, Neox allows us to just change the import statement on each reducer! No more changes. Pretty cool, huh?

import fromJS from '@neocoast/neox';
const intialState = fromJS({
loading: false,
user: {
id: 1,
username: 'tintef',
},
});
export default reducer(state = initialState, action) => {
switch (action.type) {
case 'SET_LOADING':
return state.set('loading', action.payload);
case 'SET_USER':
return state.set('user', action.payload);
}
}

Liked the idea? Check out the repository on Github!