В рамках своей работы, я не раз сталкивался с проблемой, что нужно отслеживать изменение в LocalStorage в совершенно независимых компонентах.
Были попытки отслеживания изменений через "window.addEventListener", но и тут меня ждала неудача, так как в этом случае отслеживание будет происходить только в другой вкладке браузера и тем самым я дошел до создания своего хука, назвал его - useLocalStorageEffect. Далее уже будем говорить о нем.
Какие проблемы решает хук useLocalStorageEffect:
Отслеживание изменений происходит в любом месте вашего приложения
Вам не обязательно волноваться о перезагрузке вашей страницы, для того что бы информация обновилась
Код выглядит лаконично и понятно
Обязательным элементом для использования этого хука является усовершенствованный метод для установки значения по ключу в LocalStoarge.
Метод setLocalStorageItem
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
}
Метод setLocalStorageItem решает проблему отслеживания событий в текущей вкладке браузера.
Хук useLocalStorageEffect
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 принимает два аргумента:
Функцию обработчик, которая принимает в себя 3 аргумента(ключ, новое значения, старое значение)
Массив который содержит ключи в localStorage, при изменении значений которых будет вызываться функция обработчик