useSessionStorage

Visual example

site title
domain.tld

Value is true

Code base

import { get } from "svelte/store";

import { type TsetValue, useEventListener, useState } from "@dimaslz/svelteuse"
import { parseJSON } from "@/utils";

declare global {
	interface WindowEventMap {
		"session-storage": CustomEvent;
	}
}

type TFn<T> = (f: T) => T;
type TNewState<T> = TFn<T> | T;
type UseStateOutput<T> = {
	store: SvelteStore<T>;
	update: TsetValue<T>;
	reset: () => void;
	clear: () => void;
};

export function useSessionStorage<T>(key: string, initialValue: T): UseStateOutput<T> {
	const readValue = (): T => {
		// Prevent build error "window is undefined" but keeps working
		if (typeof window === "undefined") {
			return initialValue;
		}

		try {
			const item = window.sessionStorage.getItem(key);
			window.sessionStorage.setItem(
				key,
				JSON.stringify(item ? (parseJSON(item || "false") as T) : initialValue),
			);
			return item ? (parseJSON(item || "false") as T) : initialValue;
		} catch (error) {
			console.warn(`Error reading sessionStorage key “${key}”:`, error);
			return initialValue;
		}
	};

	const [storedValue, setStoredValue] = useState<T>(readValue);

	const setValue = (value: TNewState<T>): void => {
		// Prevent build error "window is undefined" but keeps working
		if (typeof window === "undefined") {
			console.warn(
				`Tried setting sessionStorage key “${key}” even though environment is not a client`,
			);
		}

		try {
			const newValue = value instanceof Function ? value(get(storedValue)) : value;
			window.sessionStorage.setItem(key, JSON.stringify(newValue));

			window.dispatchEvent(new Event("session-storage"));
		} catch (error) {
			console.warn(`Error setting sessionStorage key “${key}”:`, error);
		}
	};

	const reset = () => {
		setValue(initialValue as T);
	};

	const clear = () => {
		window.sessionStorage.removeItem(key);
	};

	const handleStorageChange = (event: StorageEvent | CustomEvent) => {
		if ((event as StorageEvent)?.key && (event as StorageEvent).key !== key) {
			return;
		}

		setStoredValue(readValue());
	};

	useEventListener<StorageEvent | CustomEvent>("storage", handleStorageChange);

	useEventListener<StorageEvent | CustomEvent>("session-storage", handleStorageChange);

	return { store: storedValue, update: setValue, reset, clear };
}

Code example

<!-- javascript -->
<script lang="ts">
	import { useSessionStorage } from "@dimaslz/svelteuse";

	const [storageValue, updateSessionStorage] = useSessionStorage<boolean>(
		"dimaslz-svelteuse",
		true,
	);

	const toggleTheme = () => {
		updateSessionStorage((prevValue) => {
			return !prevValue;
		});
	};
</script>

<!-- html -->
<div>
	<p>
		Value is <code>{JSON.stringify($storageValue)}</code>
	</p>
	<button on:click={toggleTheme}>update state</button>
</div>