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