Writing our own hook to track changes in LocalStorage

As part of my work, I have repeatedly encountered the problem that you need to track changes in LocalStorage in completely independent components.

There were attempts to track changes through “window.addEventListener”, but even here I was unsuccessful, since in this case the tracking will only occur in another browser tab, and thus I got to creating my own hook, called it – useLocalStorageEffect. Next, we will talk about it.

What problems does the useLocalStorageEffect hook solve:

  • Change tracking happens anywhere in your application

  • You do not have to worry about reloading your page in order for the information to be updated.

  • The code looks concise and clear

A required element to use this hook is an advanced method for setting a value by key in the LocalStoarge.

setLocalStorageItem method

import _ from 'lodash'

export const setLocalStorageItem = (key, value) => {
	if (typeof window !== 'undefined') {
		if (key) {
			const data = window.localStorage.getItem(key)

			if (_.isNil(data)) {
				if (_.isUndefined(value)) {
					window.localStorage.setItem(key, null)

					return null
				}

				window.localStorage.setItem(key, JSON.stringify(value))
			}

			window.localStorage.setItem(key, JSON.stringify(value))

			const event = new StorageEvent('storage', {
				isTrusted: true,
				bubbles: true,
				cancelable: false,
				key: key,
				oldValue: data,
				newValue: JSON.stringify(value)
			})

			window.dispatchEvent(event)
		}

		return null
	}

	return null
}

The setLocalStorageItem method solves the problem of tracking events in the current browser tab.

useLocalStorageEffect Hook

import _ from 'lodash'
import { useEffect } from 'react'

const useLocalStorageEffect = (callback, deps = []) => {
	if (!_.isFunction(callback)) {
		throw new Error('Callback in useLocalStorageEffect is not a function')
	}

	if (!_.isArray(deps)) {
		throw new Error('Depends in useLocalStorageEffect is not a Array')
	}

	const storageListener = (event) => {
		if (_.size(deps) > 0 && deps.includes(_.get(event, 'key'))) {
			return callback(
				_.get(event, 'key', ''),
				JSON.parse(_.get(event, 'newValue', '')),
				JSON.parse(_.get(event, 'oldValue', ''))
			)
		}

		if (_.isArray(deps) && _.size(deps) === 0) {
			return callback(
				_.get(event, 'key', ''),
				JSON.parse(_.get(event, 'newValue', '')),
				JSON.parse(_.get(event, 'oldValue', ''))
			)
		}
	}

	useEffect(() => {
		window.addEventListener('storage', storageListener, false)

		return () => window.removeEventListener('storage', storageListener)
	}, [])
}

export default useLocalStorageEffect

useLocalStorageEffect takes two arguments:

  • A handler function that takes 3 arguments (key, new value, old value)

  • An array that contains the keys in localStorage, when the values ​​of which change, the handler function will be called

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *