Use React Hooks with Storage as Global State Management

Embbnux Ji
RingCentral Developers
3 min readMay 24, 2019
Hook & Storage

React Hooks give us a new way to manage state in React. But how to manage global state as redux and how to persist state? This article will show how to use hook for global state management with storage.

Reference the following GitHub repos for additional code:

  1. Hook library: use-global-storage
  2. Storage library: rt-storage
  3. Demo: online, project: use-global-storage-demo

React Hooks Introduce

Hooks was added in React 16.8. With hooks, we can use state and other React features without writing a class.

With useState, we can read and set state in function component:

import React, { useState } from 'react';

function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

With useEffect, we can run some function as you do in React class lifecycle methods. We can think it as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

import React, { useState, useEffect } from 'react';

function Example() {
const [count, setCount] = useState(0);

// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

Use global storage library

In this article, I will persist React state into storage, and use storage to broadcast and sync state between components and browser tabs. So we need a storage solution that support those features. localStorage is a good choice. But in some browsers, localStorage only supports 5m data. For indexedDB, it supports unlimited storage space, but doesn’t have event between tabs.

In rt-storage, it uses localStorage to broadcast event in different tabs, uses indexedDB to persist data. It is based on localforage and rxjs :

import RTStorage from 'rt-storage';

const storage = new RTStorage({ name: 'test-db' });
const subscription = storage.subscribe((event) => {
console.dir(event)
});
const storageKey = 'storageKey';
storage.getItem(storageKey).then(a => console.log(a));
storage.setItem(storageKey, data).then(() => console.log('set successfully'));
subscription.unsubscribe();

For more details, please check the project repo.

Use storage hook

So let’s start to create a customized react hook with global storage. The following is the core source code of use-global-storage:

import { useState, useEffect } from 'react';
import * as RTStorage from 'rt-storage';
export default function useGlobalStorage({ storageOptions } : { storageOptions: any }) {
const storage = new RTStorage(storageOptions);
const useStorage = (key: string, initialData: any) => {
const [data, setState] = useState(initialData);
useEffect(() => {
function handleStorageChange(data) {
setState(data);
}
storage.getItem(key).then(lastData => {
if (lastData) {
setState(lastData);
}
});
const subscription = storage.subscribe(key, handleStorageChange);
return () => {
subscription.unsubscribe();
};
}, []);
const setData = async(newData: any) => {
let newValue;
if (typeof newData === 'function') {
newValue = newData(data);
} else {
newValue = newData
}
setState(newValue);
await storage.setItem(key, newValue);
}

return [data, setData];
}
return useStorage;
};

It will return a hook function which allow user to set state into storage and sync with other components and tabs. setData function will set state into react state and save data into storage. And we use useEffect to subscribe storage changed event.

Example of using use-global-storage hook in project:

import useGlobalStorage from 'use-global-storage';

const useStorage = useGlobalStorage({
storageOptions: { name: 'test-db' }
});

const Counter = () => {
const [state, setState] = useStorage('counter');
return (
<div className="Counter">
<p>
Counter:
{state || 0}
</p>
<button type="button" onClick={() => setState(state + 1)}>
+1 to global
</button>
</div>
);
};

It is very simple to use it. Just get state and setState from useStorage hook, and your component is connected with storage data. You can get the online demo page here. To get full code, refer to this Github repo.

Conclusion

This article provides a new way to manage global state with react hooks and storage. Hope you will like this library: use-global-storage.

--

--