В этой серии статей мы отправимся в путешествие по миру пользовательских хуков React, открывая для себя их огромный потенциал для улучшения ваших проектов разработки. Сегодня мы сосредоточимся на хуке "useStorage", одном из многих тщательно разработанных хуков, доступных в коллекции пользовательских хуков React.
Github: https://github.com/sergeyleschev/react-custom-hooks
import { useCallback, useState, useEffect } from "react"
export function useLocalStorage(key, defaultValue) {
return useStorage(key, defaultValue, window.localStorage)
}
export function useSessionStorage(key, defaultValue) {
return useStorage(key, defaultValue, window.sessionStorage)
}
function useStorage(key, defaultValue, storageObject) {
const [value, setValue] = useState(() => {
const jsonValue = storageObject.getItem(key)
if (jsonValue != null) return JSON.parse(jsonValue)
if (typeof defaultValue === "function") {
return defaultValue()
} else {
return defaultValue
}
})
useEffect(() => {
if (value === undefined) return storageObject.removeItem(key)
storageObject.setItem(key, JSON.stringify(value))
}, [key, value, storageObject])
const remove = useCallback(() => {
setValue(undefined)
}, [])
return [value, setValue, remove]
}
Хук useStorage предоставляет две удобные функции: useLocalStorage и useSessionStorage. С помощью useLocalStorage вы можете без особых усилий сохранять и извлекать данные в локальном хранилище браузера, в то время как useSessionStorage предлагает ту же функциональность, но вместо этого использует хранилище сеансов.
Одним из ключевых преимуществ этого хука является его простота. Вы можете использовать его для хранения данных любого типа, таких как строки, числа или даже сложные объекты, всего с помощью нескольких строк кода. Кроме того, useStorage выполняет сериализацию и десериализацию данных, поэтому вам не нужно беспокоиться о преобразовании значений в формат JSON и обратно.
Еще одним преимуществом является автоматическая синхронизация между сохраненными данными и состоянием компонента. Всякий раз, когда изменяются сохраненные данные, хук соответствующим образом обновляет состояние компонента. Аналогично, при изменении состояния компонента хук автоматически сохраняет новое значение в хранилище. Такая двунаправленная синхронизация гарантирует, что в вашем приложении всегда будут отображаться самые свежие данные, что делает его идеальным для сценариев, где обновления в режиме реального времени имеют решающее значение.
Хук useStorage также предоставляет функцию удаления, позволяющую легко удалять сохраненные значения, когда они больше не нужны. Эта функциональность удобна при реализации таких функций, как кнопки выхода из системы или очистка пользовательских данных.
import { useSessionStorage, useLocalStorage } from "./useStorage"
export default function StorageComponent() {
const [name, setName, removeName] = useSessionStorage("name", "Sergey")
const [age, setAge, removeAge] = useLocalStorage("age", 26)
return (
<div>
<div>
{name} - {age}
</div>
<button onClick={() => setName("John")}>Set Name</button>
<button onClick={() => setAge(40)}>Set Age</button>
<button onClick={removeName}>Remove Name</button>
<button onClick={removeAge}>Remove Age</button>
</div>
)
}
Вы можете использовать хук useStorage в различных сценариях. Например, представьте, что у вас есть панель настроек, на которой пользователи могут настраивать свои предпочтения. Используя useLocalStorage, вы можете легко сохранять и извлекать эти настройки, гарантируя, что они будут сохраняться при перезагрузке страницы или даже если пользователь закроет и снова откроет браузер.
Full Version | React Custom Hooks: https://habr.com/en/articles/746760/
Комментарии (5)
sovaz1997
21.08.2025 06:26Как будто слишком специфичный хук, чтобы использовать именно для session storage и local storage и ни для чего другого.
А что, если я хочу на сервере иметь какое-то хранилище и синькать его?
Тут как будто бы напрашивается более абстрактный интерфейс для хранилища + работа с асинхронщиной. А сериализацию/десериализацию поместить в другое место и к примеру использовать только в local storage и session storage.
Второй момент: что если я захочу использовать хук в 2 независимых компонентах, и при этом у меня будет один ключ? Тут мы потеряем реактивность, если обновим в одном компоненте. А это, как по мне, очень важная штука.
Вообще всё уже придумано по сути: useSyncExternalStore. А на него уже можно какие угодно абстракции накручивать.
GCU
Для "тщательно разработанных" выглядит странно. Отдельный remove выглядит избыточным, выставление undefined ведь делает то же самое.
Не понимаю почему в хранилище нельзя писать сразу синхронно, просто вернув обёртку над сеттером из стейта и сразу же ловить ошибку, зачем эффект?
Эффект нужен для другого - так как хранилище общее, а компонентов которым оно нужно может быть несколько, то нужно как-то узнавать об изменениях. Про это вообще думали?
winkyBrain
это перевод, автор вам вряд ли ответит по делу) писалось не для дискуссий
GCU
Да, извиняюсь - как-то пропустил этот момент. К качеству перевода претензий нет.