В рамках своей работы, я не раз сталкивался с проблемой, что нужно отслеживать изменение в 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, при изменении значений которых будет вызываться функция обработчик
