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

Комментарии (4)