Skip to content

Commit

Permalink
fix: improve storage hook typing
Browse files Browse the repository at this point in the history
  • Loading branch information
SukkaW committed Jun 7, 2024
1 parent 81d6b83 commit 3c4515e
Showing 1 changed file with 25 additions and 4 deletions.
29 changes: 25 additions & 4 deletions src/create-storage-hook/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'client-only';
import { useSyncExternalStore, useCallback, useMemo } from 'react';
import { noop } from '../noop';
import { useIsomorphicLayoutEffect } from '../use-isomorphic-layout-effect';
import { useLayoutEffect } from '../use-isomorphic-layout-effect';
import { noSSRError } from '../no-ssr';

type StorageType = 'localStorage' | 'sessionStorage';
Expand Down Expand Up @@ -101,14 +101,26 @@ export function createStorage(type: StorageType) {
[key, serializer]
);

// ssr compatible
function useStorage<T>(
key: string,
serverValue: NotUndefined<T>,
options?: UseStorageRawOption | UseStorageParserOption<T>
): readonly [NotUndefined<T>, React.Dispatch<React.SetStateAction<T | null>>];
// client-render only
function useStorage<T>(
key: string,
serverValue?: undefined,
options?: UseStorageRawOption | UseStorageParserOption<T>
): readonly [NotUndefined<T> | null, React.Dispatch<React.SetStateAction<T | null>>];
function useStorage<T>(
key: string,
serverValue?: NotUndefined<T> | undefined,
options: UseStorageRawOption | UseStorageParserOption<T> = {
serializer: JSON.stringify,
deserializer: JSON.parse
}
) {
): readonly [T | null, React.Dispatch<React.SetStateAction<T | null>>] | readonly [T, React.Dispatch<React.SetStateAction<T | null>>] {
const subscribeToSpecificKeyOfLocalStorage = useCallback((callback: () => void) => {
if (typeof window === 'undefined') {
return noop;
Expand Down Expand Up @@ -174,7 +186,7 @@ export function createStorage(type: StorageType) {
[key, serializer, deserialized]
);

useIsomorphicLayoutEffect(() => {
useLayoutEffect(() => {
if (
getStorageItem(key) === null
&& serverValue !== undefined
Expand All @@ -183,7 +195,16 @@ export function createStorage(type: StorageType) {
}
}, [deserializer, key, serializer, serverValue]);

return [deserialized ?? serverValue ?? null, setState] as const;
const finalValue: T | null = deserialized === null
// storage doesn't have value
? (serverValue === undefined
// no default value provided
? null
: serverValue satisfies NotUndefined<T>)
// storage has value
: deserialized satisfies T;

return [finalValue, setState] as const;
}

return {
Expand Down

0 comments on commit 3c4515e

Please sign in to comment.